// NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #include "std3d.h" #include "nel/3d/scene_group.h" #include "nel/misc/stream.h" #include "nel/misc/matrix.h" #include "nel/3d/scene.h" #include "nel/3d/transform_shape.h" #include "nel/3d/mesh_instance.h" #include "nel/3d/shape_bank.h" #include "nel/3d/u_instance_group.h" #include "nel/3d/vertex_buffer.h" #include "nel/3d/index_buffer.h" #include "nel/3d/text_context.h" #include "nel/3d/water_model.h" #include "nel/3d/water_shape.h" #include "nel/misc/polygon.h" #include "nel/misc/path.h" using namespace NLMISC; using namespace std; namespace NL3D { // --------------------------------------------------------------------------- // CInstance // --------------------------------------------------------------------------- // *************************************************************************** CInstanceGroup::CInstance::CInstance () { /* *********************************************** * WARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance * It can be loaded/called through CAsyncFileManager for instance * ***********************************************/ DontAddToScene = false; AvoidStaticLightPreCompute= false; StaticLightEnabled= false; DontCastShadow= false; LocalAmbientId= 0xFF; DontCastShadowForInterior= false; DontCastShadowForExterior= false; Visible= true; } // *************************************************************************** void CInstanceGroup::CInstance::serial (NLMISC::IStream& f) { /* *********************************************** * WARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance * It can be loaded/called through CAsyncFileManager for instance * ***********************************************/ /* Version 7: - Visible Version 6: - DontCastShadowForExterior Version 5: - DontCastShadowForInterior Version 4: - LocalAmbientId. Version 3: - StaticLight. Version 2: - gameDev data. Version 1: - Clusters */ // Serial a version number sint version=f.serialVersion (7); // Visible if (version >= 7) f.serial(Visible); // DontCastShadowForExterior if (version >= 6) f.serial(DontCastShadowForExterior); else DontCastShadowForExterior= false; // DontCastShadowForInterior if (version >= 5) f.serial(DontCastShadowForInterior); else DontCastShadowForInterior= false; // Serial the LocalAmbientId. if (version >= 4) { f.serial(LocalAmbientId); } else if(f.isReading()) { LocalAmbientId= 0xFF; } // Serial the StaticLight if (version >= 3) { f.serial (AvoidStaticLightPreCompute); f.serial (DontCastShadow); f.serial (StaticLightEnabled); f.serial (SunContribution); nlassert(CInstanceGroup::NumStaticLightPerInstance==2); f.serial (Light[0]); f.serial (Light[1]); } else if(f.isReading()) { AvoidStaticLightPreCompute= false; StaticLightEnabled= false; DontCastShadow= false; } // Serial the gamedev data if (version >= 2) { f.serial (InstanceName); f.serial (DontAddToScene); } // Serial the clusters if (version >= 1) f.serialCont (Clusters); // Serial the name f.serial (Name); // Serial the position vector f.serial (Pos); // Serial the rotation vector f.serial (Rot); // Serial the scale vector f.serial (Scale); // Serial the parent location in the vector (-1 if no parent) f.serial (nParent); } // --------------------------------------------------------------------------- // CInstanceGroup // --------------------------------------------------------------------------- // *************************************************************************** uint CInstanceGroup::getNumInstance () const { return (uint)_InstancesInfos.size(); } // *************************************************************************** const string& CInstanceGroup::getShapeName (uint instanceNb) const { // Return the name of the n-th instance return _InstancesInfos[instanceNb].Name; } // *************************************************************************** const string& CInstanceGroup::getInstanceName (uint instanceNb) const { // Return the name of the n-th instance return _InstancesInfos[instanceNb].InstanceName; } // *************************************************************************** const CVector& CInstanceGroup::getInstancePos (uint instanceNb) const { // Return the position vector of the n-th instance return _InstancesInfos[instanceNb].Pos; } // *************************************************************************** const CQuat& CInstanceGroup::getInstanceRot (uint instanceNb) const { // Return the rotation vector of the n-th instance return _InstancesInfos[instanceNb].Rot; } // *************************************************************************** const CVector& CInstanceGroup::getInstanceScale (uint instanceNb) const { // Return the scale vector of the n-th instance return _InstancesInfos[instanceNb].Scale; } // *************************************************************************** void CInstanceGroup::getInstanceMatrix(uint instanceNb,NLMISC::CMatrix &dest) const { dest.identity(); dest.translate(getInstancePos(instanceNb)); dest.rotate(getInstanceRot(instanceNb)); dest.scale(getInstanceScale(instanceNb)); } // *************************************************************************** sint32 CInstanceGroup::getInstanceParent (uint instanceNb) const { // Return the scale vector of the n-th instance return _InstancesInfos[instanceNb].nParent; } // *************************************************************************** const CInstanceGroup::CInstance &CInstanceGroup::getInstance(uint instanceNb) const { return _InstancesInfos[instanceNb]; } // *************************************************************************** CInstanceGroup::CInstance &CInstanceGroup::getInstance(uint instanceNb) { return _InstancesInfos[instanceNb]; } // *************************************************************************** CTransformShape *CInstanceGroup::getTransformShape(uint instanceNb) const { if(instanceNb>_Instances.size()) return NULL; return _Instances[instanceNb]; } // *************************************************************************** CInstanceGroup::CInstanceGroup() { /* *********************************************** * WARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance * It can be loaded/called through CAsyncFileManager for instance * ***********************************************/ _IGSurfaceLight.setOwner(this); _GlobalPos = CVector(0,0,0); _Root = NULL; _ClusterSystemForInstances = NULL; _ParentClusterSystem = NULL; _RealTimeSunContribution= true; _AddToSceneState = StateNotAdded; _TransformName = NULL; _AddRemoveInstance = NULL; _IGAddBeginCallback = NULL; _UserIg= NULL; } // *************************************************************************** CInstanceGroup::~CInstanceGroup() { /* *********************************************** * WARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance * It can be loaded/called through CAsyncFileManager for instance * ***********************************************/ } // *************************************************************************** void CInstanceGroup::build (const CVector &vGlobalPos, const TInstanceArray& array, const std::vector& Clusters, const std::vector& Portals, const std::vector &pointLightList, const CIGSurfaceLight::TRetrieverGridMap *retrieverGridMap, float igSurfaceLightCellSize) { _GlobalPos = vGlobalPos; // Copy the array _InstancesInfos = array; _Portals = Portals; _ClusterInfos = Clusters; // Link portals and clusters uint32 i, j, k; for (i = 0; i < _Portals.size(); ++i) { for (j = 0; j < _ClusterInfos.size(); ++j) { bool bPortalInCluster = true; for (k = 0; k < _Portals[i]._Poly.size(); ++k) if (!_ClusterInfos[j].isIn (_Portals[i]._Poly[k]) ) { bPortalInCluster = false; break; } if (bPortalInCluster) { _Portals[i].setCluster(&_ClusterInfos[j]); _ClusterInfos[j].link (&_Portals[i]); } } } // Create Meta Cluster if needed /* CCluster clusterTemp; bool mustAdd = false; for (i = 0; i < _Portals.size(); ++i) if (_Portals[i].getNbCluster() == 1) { mustAdd = true; break; } if (mustAdd) { CCluster clusterTemp; _ClusterInfos.push_back(clusterTemp); CCluster *pMetaCluster = &_ClusterInfos[_ClusterInfos.size()-1]; pMetaCluster->setMetaCluster(); for (i = 0; i < _Portals.size(); ++i) if (_Portals[i].getNbCluster() == 1) { _Portals[i].setCluster(pMetaCluster); pMetaCluster->link(&_Portals[i]); } }*/ // Build the list of light. NB: sort by LightGroupName the array. std::vector plRemap; buildPointLightList(pointLightList, plRemap); // Build IgSurfaceLight // clear _IGSurfaceLight.clear(); if(retrieverGridMap) { //build _IGSurfaceLight.build(*retrieverGridMap, igSurfaceLightCellSize, plRemap); } } // *************************************************************************** void CInstanceGroup::build (const CVector &vGlobalPos, const TInstanceArray& array, const std::vector& Clusters, const std::vector& Portals) { // empty pointLightList std::vector pointLightList; build(vGlobalPos, array, Clusters, Portals, pointLightList); } // *************************************************************************** void CInstanceGroup::retrieve (CVector &vGlobalPos, TInstanceArray& array, std::vector& Clusters, std::vector& Portals, std::vector &pointLightList) const { // Just copy infos. NB: light information order have change but is still valid vGlobalPos= _GlobalPos; array= _InstancesInfos; Portals= _Portals; Clusters= _ClusterInfos; // Must reset links to all portals and clusters. uint i; for(i=0; i= 5) { f.serial(_RealTimeSunContribution); } else if(f.isReading()) { _RealTimeSunContribution= true; } // Serial the IGSurfaceLight if (version >= 4) { f.serial(_IGSurfaceLight); } else if(f.isReading()) { _IGSurfaceLight.clear(); } // Serial the PointLights info if (version >= 3) { f.serial(_PointLightArray); } else if(f.isReading()) { _PointLightArray.clear(); } if (version >= 2) f.serial(_GlobalPos); if (version >= 1) { f.serialCont (_ClusterInfos); f.serialCont (_Portals); // Links if (f.isReading()) { uint32 i, j; for (i = 0; i < _ClusterInfos.size(); ++i) { uint32 nNbPortals; f.serial (nNbPortals); _ClusterInfos[i]._Portals.resize (nNbPortals); // Recreate clusters to portals links for (j = 0; j < nNbPortals; ++j) { sint32 nPortalNb; f.serial (nPortalNb); _ClusterInfos[i]._Portals[j] = &_Portals[nPortalNb]; _Portals[nPortalNb].setCluster (&_ClusterInfos[i]); } } } else // We are writing to the stream { uint32 i, j; for (i = 0; i < _ClusterInfos.size(); ++i) { uint32 nNbPortals = (uint32)_ClusterInfos[i]._Portals.size(); f.serial (nNbPortals); for (j = 0; j < nNbPortals; ++j) { sint32 nPortalNb = (sint32)(_ClusterInfos[i]._Portals[j] - &_Portals[0]); f.serial (nPortalNb); } } } } // Serial the array f.serialCont (_InstancesInfos); } // *************************************************************************** void CInstanceGroup::createRoot (CScene& scene) { _Root = (CTransform*)scene.createModel (TransformId); _Root->setDontUnfreezeChildren (true); setPos (CVector(0,0,0)); } // *************************************************************************** void CInstanceGroup::setTransformNameCallback (ITransformName *pTN) { _TransformName = pTN; } // *************************************************************************** void CInstanceGroup::setAddRemoveInstanceCallback(IAddRemoveInstance *callback) { _AddRemoveInstance = callback; } // *************************************************************************** void CInstanceGroup::setIGAddBeginCallback(IIGAddBegin *callback) { _IGAddBeginCallback = callback; } // *************************************************************************** bool CInstanceGroup::addToScene (CScene& scene, IDriver *driver, uint selectedTexture) { // Init the scene lights _PointLightArray.initAnimatedLightIndex (scene); uint32 i, j; // Test if portals are linked to their 2 clusters for (i = 0; i < _Portals.size(); ++i) for (j = 0; j < 2; ++j) { if (_Portals[i]._Clusters[j] == NULL) { nlwarning("Portal %d (name:%s) is not linked to 2 clusters. Instance Group Not Added To Scene.", i, _Portals[i].getName().c_str()); } } _Instances.resize (_InstancesInfos.size(), NULL); if (_IGAddBeginCallback) _IGAddBeginCallback->startAddingIG((uint)_InstancesInfos.size()); // Creation and positionning of the new instance vector::iterator it = _InstancesInfos.begin(); // Water surface may have a callback when they are created, and this callback need their position // Their position isn't set right now however, so must call that callback later IWaterSurfaceAddedCallback *oldCallback = scene.getWaterCallback(); scene.setWaterCallback(NULL); for (i = 0; i < _InstancesInfos.size(); ++i, ++it) { // Get the shape name string shapeName; getShapeName (i, shapeName); if (!shapeName.empty ()) { if (!_InstancesInfos[i].DontAddToScene) { // TMP FIX : some pacs_prim files where exported ... if (nlstricmp(NLMISC::CFile::getExtension(shapeName), "pacs_prim") == 0) { nlwarning("Can't read %s (not a shape)", shapeName.c_str()); _Instances[i] = NULL; } else { _Instances[i] = scene.createInstance (shapeName); } if( _Instances[i] == NULL ) { nlwarning("Not found '%s' file", shapeName.c_str()); } } } } scene.setWaterCallback(oldCallback); return addToSceneWhenAllShapesLoaded (scene, driver, selectedTexture); } // *************************************************************************** void CInstanceGroup::getShapeName (uint instanceIndex, std::string &shapeName) const { const CInstance &rInstanceInfo = _InstancesInfos[instanceIndex]; shapeName = rInstanceInfo.Name; // If there is a callback added to this instance group then transform // the name of the shape to load. if (_TransformName != NULL && !rInstanceInfo.InstanceName.empty()) { shapeName = _TransformName->transformName (instanceIndex, rInstanceInfo.InstanceName, rInstanceInfo.Name); } toLower(shapeName); if (!shapeName.empty() && shapeName.find('.') == std::string::npos) shapeName += ".shape"; } // *************************************************************************** // Private method bool CInstanceGroup::addToSceneWhenAllShapesLoaded (CScene& scene, IDriver *driver, uint selectedTexture) { uint32 i, j; vector::iterator it = _InstancesInfos.begin(); for (i = 0; i < _InstancesInfos.size(); ++i, ++it) { CInstance &rInstanceInfo = *it; if (!rInstanceInfo.DontAddToScene) { if (_Instances[i]) { _Instances[i]->setPos (rInstanceInfo.Pos); _Instances[i]->setRotQuat (rInstanceInfo.Rot); _Instances[i]->setScale (rInstanceInfo.Scale); _Instances[i]->setPivot (CVector::Null); if(rInstanceInfo.Visible) _Instances[i]->show(); else _Instances[i]->hide(); if (scene.getWaterCallback()) { CWaterModel *wm = dynamic_cast(_Instances[i]); if (wm) { const CWaterShape *ws = safe_cast((const IShape *) wm->Shape); scene.getWaterCallback()->waterSurfaceAdded(ws->getShape(), wm->getMatrix(), ws->isSplashEnabled(), ws->getUseSceneWaterEnvMap(0) || ws->getUseSceneWaterEnvMap(1)); } } // Static Light Setup if( rInstanceInfo.StaticLightEnabled ) { // Count lights. uint numPointLights; for(numPointLights= 0; numPointLightsfreezeStaticLightSetup(pls, numPointLights, rInstanceInfo.SunContribution, frozenAmbientlight); } // Driver not NULL ? if (driver) { // Flush shape's texture with this driver _Instances[i]->Shape->flushTextures (*driver, selectedTexture); } } } else { _Instances[i] = NULL; } } // Setup the hierarchy // We just have to set the traversal HRC (Hierarchy) if (_Root == NULL) { createRoot (scene); } it = _InstancesInfos.begin(); for (i = 0; i < _InstancesInfos.size(); ++i, ++it) if (!_InstancesInfos[i].DontAddToScene && _Instances[i] != NULL) { CInstance &rInstanceInfo = *it; if( rInstanceInfo.nParent != -1 ) // Is the instance get a parent _Instances[rInstanceInfo.nParent]->hrcLinkSon( _Instances[i] ); else _Root->hrcLinkSon( _Instances[i] ); } // Attach the root of the instance group to the root of the hierarchy traversal scene.getRoot()->hrcLinkSon( _Root ); // Cluster / Portals // ----------------- CClipTrav *pClipTrav = &scene.getClipTrav(); _ClipTrav = pClipTrav; // Create the MOT links (create the physical clusters) _ClusterInstances.resize (_ClusterInfos.size()); for (i = 0; i < _ClusterInstances.size(); ++i) { _ClusterInstances[i] = (CCluster*)scene.createModel (ClusterId); _ClusterInstances[i]->Group = this; _ClusterInstances[i]->_Portals = _ClusterInfos[i]._Portals; _ClusterInstances[i]->_LocalVolume = _ClusterInfos[i]._LocalVolume; _ClusterInstances[i]->_LocalBBox = _ClusterInfos[i]._LocalBBox; _ClusterInstances[i]->_Volume = _ClusterInfos[i]._Volume; _ClusterInstances[i]->_BBox = _ClusterInfos[i]._BBox; _ClusterInstances[i]->FatherVisible = _ClusterInfos[i].FatherVisible; _ClusterInstances[i]->VisibleFromFather = _ClusterInfos[i].VisibleFromFather; _ClusterInstances[i]->FatherAudible = _ClusterInfos[i].FatherAudible; _ClusterInstances[i]->AudibleFromFather = _ClusterInfos[i].AudibleFromFather; _ClusterInstances[i]->Name = _ClusterInfos[i].Name; _ClusterInstances[i]->setSoundGroup(_ClusterInfos[i].getSoundGroup()); _ClusterInstances[i]->setEnvironmentFx(_ClusterInfos[i].getEnvironmentFx()); pClipTrav->registerCluster (_ClusterInstances[i]); _ClusterInstances[i]->clipUnlinkFromAll(); } // Relink portals with newly created clusters for (i = 0; i < _Portals.size(); ++i) for (j = 0; j < 2; ++j) { if (_Portals[i]._Clusters[j]) { sint32 nClusterNb; nClusterNb = (sint32)(_Portals[i]._Clusters[j] - &_ClusterInfos[0]); _Portals[i]._Clusters[j] = _ClusterInstances[nClusterNb]; } } // Link shapes to clusters for (i = 0; i < _Instances.size(); ++i) if (_Instances[i] != NULL && !_InstancesInfos[i].DontAddToScene) { if (_InstancesInfos[i].Clusters.size() > 0) { _Instances[i]->clipUnlinkFromAll(); for (j = 0; j < _InstancesInfos[i].Clusters.size(); ++j) { uint32 clusterInst = _InstancesInfos[i].Clusters[j]; if (clusterInst < _ClusterInstances.size()) _ClusterInstances[clusterInst]->clipAddChild( _Instances[i] ); else nlwarning("IG: BUG: Cluster infos size %u, indexing %u", (uint32)_ClusterInstances.size(), clusterInst); } // For the first time we have to set all the instances to NOT move (and not be rebinded) _Instances[i]->freeze(); _Instances[i]->setClusterSystem (this); } else { // These instances are not attached to a cluster at this level so we cannot freeze them // Moreover we must set their clustersystem they will be tested against _Instances[i]->setClusterSystem (_ClusterSystemForInstances); } } _Root->freeze(); // HRC OBS like for (i = 0; i < _ClusterInstances.size(); ++i) { _ClusterInstances[i]->setWorldMatrix (_Root->getMatrix()); for (j = 0; j < _ClusterInstances[i]->getNbPortals(); ++j) { CPortal *pPortal = _ClusterInstances[i]->getPortal(j); pPortal->setWorldMatrix (_Root->getMatrix()); } // Re affect the cluster to the accelerator if not the root if (!_ClusterInstances[i]->isRoot()) { _ClipTrav->unregisterCluster(_ClusterInstances[i]); _ClipTrav->registerCluster (_ClusterInstances[i]); } } // Link the instance group to the parent linkToParent (scene.getGlobalInstanceGroup()); // Attach the clusters to the root of the instance group for (i = 0; i < _ClusterInstances.size(); ++i) _Root->hrcLinkSon( _ClusterInstances[i] ); // Default: freezeHRC all instances. freezeHRC(); // Register the instanceGroup for light animation // ----------------- // If some PointLight to animate if(_PointLightArray.getPointLights().size() > 0) scene.addInstanceGroupForLightAnimation(this); _AddToSceneState = StateAdded; if (_AddRemoveInstance) _AddRemoveInstance->instanceGroupAdded(); return true; } // *************************************************************************** bool CInstanceGroup::addToSceneAsync (CScene& scene, IDriver *driver, uint selectedTexture) { // Init the scene lights _PointLightArray.initAnimatedLightIndex (scene); uint32 i; _AddToSceneState = StateAdding; _AddToSceneTempScene = &scene; _AddToSceneTempDriver = driver; _AddToSceneTempSelectTexture = selectedTexture; _Instances.resize (_InstancesInfos.size(), NULL); if (_IGAddBeginCallback) _IGAddBeginCallback->startAddingIG((uint)_InstancesInfos.size()); // Creation and positionning of the new instance vector::iterator it = _InstancesInfos.begin(); set allShapesToLoad; _AddToSceneSignal = false; bool loadAsyncStarted = false; for (i = 0; i < _InstancesInfos.size(); ++i, ++it) { CInstance &rInstanceInfo = *it; if (!rInstanceInfo.DontAddToScene) { string shapeName = rInstanceInfo.Name; if (_TransformName != NULL && !rInstanceInfo.InstanceName.empty()) { shapeName = _TransformName->transformName (i, rInstanceInfo.InstanceName, rInstanceInfo.Name); } toLower(shapeName); if (!shapeName.empty() && shapeName.find('.') == std::string::npos) shapeName += ".shape"; if (allShapesToLoad.find(shapeName) == allShapesToLoad.end()) { allShapesToLoad.insert (shapeName); if (scene.getShapeBank()->getPresentState(shapeName) != CShapeBank::Present) { // Load it from file asynchronously scene.getShapeBank()->loadAsync (shapeName, scene.getDriver(), rInstanceInfo.Pos, &_AddToSceneSignal, selectedTexture); loadAsyncStarted = true; } } } } if (!loadAsyncStarted) _AddToSceneSignal = true; else _AddToSceneSignal = false; //CAsyncFileManager::getInstance().signal (&_AddToSceneSignal); return true; } // *************************************************************************** void CInstanceGroup::stopAddToSceneAsync () { if (_AddToSceneState != StateAdding) return; vector::iterator it = _InstancesInfos.begin(); CAsyncFileManager::getInstance().cancelSignal (&_AddToSceneSignal); for (uint32 i = 0; i < _InstancesInfos.size(); ++i, ++it) { CInstance &rInstanceInfo = *it; if (!rInstanceInfo.DontAddToScene) { string shapeName; bool getShapeName = true; if (_TransformName != NULL && !rInstanceInfo.InstanceName.empty()) { shapeName = _TransformName->transformName (i, rInstanceInfo.InstanceName, rInstanceInfo.Name); if (shapeName != rInstanceInfo.Name) getShapeName = false; } if (getShapeName) { if (rInstanceInfo.Name.find('.') == std::string::npos) shapeName = rInstanceInfo.Name + ".shape"; else // extension has already been added shapeName = rInstanceInfo.Name; } toLower(shapeName); _AddToSceneTempScene->getShapeBank()->cancelLoadAsync (shapeName); } } _AddToSceneState = StateNotAdded; } // *************************************************************************** CInstanceGroup::TState CInstanceGroup::getAddToSceneState () { // If we are adding but we have finished loading shapes (all shapes are here) if (_AddToSceneState == StateAdding) { if (_AddToSceneSignal) { addToScene (*_AddToSceneTempScene, _AddToSceneTempDriver, _AddToSceneTempSelectTexture); } } return _AddToSceneState; } // *************************************************************************** // Search in the hierarchy of ig the most low level (child) ig that contains the clusters that // are flagged to be visible from father or which father is visible bool CInstanceGroup::linkToParent (CInstanceGroup *pFather) { uint32 i, j; bool ret; /* for (i = 0; i < pFather->_ClusterInstances.size(); ++i) { for(j = 0; j < pFather->_ClusterInstances[i]->Children.size(); ++j) { if (linkToParent(pFather->_ClusterInstances[i]->Children[j]->Group)) return true; } } */ ret = false; if (this != pFather) { for (j = 0; j < this->_ClusterInstances.size(); ++j) { if ((this->_ClusterInstances[j]->FatherVisible) || (this->_ClusterInstances[j]->VisibleFromFather)) { for (i = 0; i < pFather->_ClusterInstances .size(); ++i) { // If my cluster j is in the cluster i of the father if (pFather->_ClusterInstances[i]->isIn(this->_ClusterInstances[j]->getBBox())) { if (this->_ClusterInstances[j]->Father != pFather->_ClusterInstances[i]) // and not already son of the father cluster ? { // unlink from parent this->_ClusterInstances[j]->unlinkFromParent(); // relink to the new father found pFather->_ClusterInstances[i]->Children.push_back(this->_ClusterInstances[j]); this->_ClusterInstances[j]->Father = pFather->_ClusterInstances[i]; } ret = true; } } } } } // store new parent if(ret) _ParentClusterSystem= pFather; return ret; } // *************************************************************************** bool CInstanceGroup::removeFromScene (CScene& scene) { uint32 i, j, k; // Remove shapes for (i = 0; i < _Instances.size(); ++i) { CTransformShape *pTShape = _Instances[i]; if(pTShape) { // For security, unfreeze any StaticLightSetup setuped. pTShape->unfreezeStaticLightSetup(); // delete the instance scene.deleteInstance (pTShape); _Instances[i] = NULL; } } // Relink portals with old clusters for (i = 0; i < _Portals.size(); ++i) for (k = 0; k < 2; ++k) { if (_Portals[i]._Clusters[k]) { for (j = 0; j < _ClusterInstances.size(); ++j) if( _Portals[i]._Clusters[k] == _ClusterInstances[j] ) break; nlassert (j!=_ClusterInstances.size()); _Portals[i]._Clusters[k] = &_ClusterInfos[j]; } } // Remove clusters CClipTrav *pClipTrav = &scene.getClipTrav(); for (i = 0; i < _ClusterInstances.size(); ++i) { pClipTrav->unregisterCluster (_ClusterInstances[i]); scene.deleteModel (_ClusterInstances[i]); } scene.deleteModel (_Root); _Root = NULL; // UnRegister the instanceGroup for light animation // ----------------- // If some PointLight to animate if(_PointLightArray.getPointLights().size() > 0) scene.removeInstanceGroupForLightAnimation(this); if (_AddRemoveInstance) _AddRemoveInstance->instanceGroupRemoved(); return true; } // *************************************************************************** void CInstanceGroup::getLights( set &LightNames ) { LightNames.clear(); for( uint32 i = 0; i < _Instances.size(); ++i ) { CMeshInstance *pMI = dynamic_cast(_Instances[i]); if( pMI != NULL ) { uint32 nNbLM = pMI->getNbLightMap(); for( uint32 j = 0; j < nNbLM; ++j ) { string sTmp; pMI->getLightMapName( j, sTmp ); set::iterator itSet = LightNames.find(sTmp); if( itSet == LightNames.end() ) LightNames.insert( sTmp ); } } } } // *************************************************************************** void CInstanceGroup::getBlendShapes( set &BlendShapeNames ) { BlendShapeNames.clear(); for( uint32 i = 0; i < _Instances.size(); ++i ) { CMeshBaseInstance *pMBI = dynamic_cast(_Instances[i]); if (pMBI != NULL) { uint32 nNbBS = pMBI->getNbBlendShape(); for( uint32 j = 0; j < nNbBS; ++j ) { string sTmp; pMBI->getBlendShapeName( j, sTmp ); set::iterator itSet = BlendShapeNames.find(sTmp); if( itSet == BlendShapeNames.end() ) BlendShapeNames.insert( sTmp ); } } } } // *************************************************************************** void CInstanceGroup::setBlendShapeFactor( const string &BlendShapeName, float rFactor ) { for( uint32 i = 0; i < _Instances.size(); ++i ) { CMeshBaseInstance *pMI = dynamic_cast(_Instances[i]); if( pMI != NULL ) { pMI->setBlendShapeFactor( BlendShapeName, rFactor ); } } } // *************************************************************************** void CInstanceGroup::addCluster(CCluster *pCluster) { _ClusterInstances.push_back(pCluster); } // *************************************************************************** void CInstanceGroup::setClusterSystemForInstances(CInstanceGroup *pIG) { _ClusterSystemForInstances = pIG; for (uint32 i = 0; i < _Instances.size(); ++i) if (_Instances[i] && _InstancesInfos[i].Clusters.size() == 0) _Instances[i]->setClusterSystem (_ClusterSystemForInstances); } // *************************************************************************** void CInstanceGroup::getDynamicPortals (std::vector &names) { for (uint32 i = 0; i < _Portals.size(); ++i) if (_Portals[i].getName() != "") names.push_back (_Portals[i].getName()); } // *************************************************************************** void CInstanceGroup::setDynamicPortal (std::string& name, bool opened) { for (uint32 i = 0; i < _Portals.size(); ++i) if (_Portals[i].getName() == name) _Portals[i].open (opened); } // *************************************************************************** bool CInstanceGroup::getDynamicPortal (std::string& name) { for (uint32 i = 0; i < _Portals.size(); ++i) if (_Portals[i].getName() == name) return _Portals[i].isOpened (); return false; } // *************************************************************************** void CInstanceGroup::setPos (const CVector &pos) { if (_Root != NULL) /// \todo Make this work (precision): _Root->setPos (_GlobalPos+pos); _Root->setPos (pos); } // *************************************************************************** void CInstanceGroup::setRotQuat (const CQuat &quat) { if (_Root != NULL) _Root->setRotQuat (quat); } // *************************************************************************** CVector CInstanceGroup::getPos () { if (_Root != NULL) return _Root->getPos (); else return CVector(0.0f, 0.0f, 0.0f); } // *************************************************************************** CQuat CInstanceGroup::getRotQuat () { if (_Root != NULL) return _Root->getRotQuat (); else return CQuat(); } // *************************************************************************** void CInstanceGroup::linkRoot (CScene &/* scene */, CTransform *father) { if(_Root) { father->hrcLinkSon( _Root ); } } // *************************************************************************** void CInstanceGroup::freezeHRC() { // For all instances. for (uint i=0; i < _Instances.size(); i++) { if(_Instances[i]) _Instances[i]->freezeHRC(); } // and for root. _Root->freezeHRC(); } // *************************************************************************** void CInstanceGroup::unfreezeHRC() { // For all instances. for (uint i=0; i < _Instances.size(); i++) { if(_Instances[i]) _Instances[i]->unfreezeHRC(); } // and for root. _Root->unfreezeHRC(); } // *************************************************************************** // *************************************************************************** // *************************************************************************** // *************************************************************************** // *************************************************************************** void CInstanceGroup::buildPointLightList(const std::vector &pointLightList, std::vector &plRemap) { // build. _PointLightArray.build(pointLightList, plRemap); // remap Instance precalc lighted. for(uint i=0; i<_InstancesInfos.size(); i++) { CInstance &inst= _InstancesInfos[i]; // If the instance has no precomputed lighting, skip if(!inst.StaticLightEnabled) continue; // remap pointlights for(uint l=0; lsetupModelMatrix(CMatrix::Identity); // For all clusters uint i; for(i=0;i<_ClusterInstances.size();i++) { CCluster *cluster= _ClusterInstances[i]; if(cluster) { uint numTotalVertices= 0; // **** Build a set of polys representing the volume (slow but debug!) static std::vector polygons; polygons.clear(); polygons.resize(cluster->_Volume.size()); // for each plane, build the associated polygon uint j; for(j=0;j_Volume[j]; p.normalize(); CVector quadCenter= p.project(cluster->_BBox.getCenter()); // choose a basis on this plane CMatrix mat; mat.setArbitraryRotK(p.getNormal()); mat.setPos(quadCenter); // Build the initial Big quad CPolygon &poly= polygons[j]; poly.Vertices.resize(4); float s= 10 * cluster->_BBox.getRadius(); poly.Vertices[0]= mat * CVector(-s,-s,0); poly.Vertices[1]= mat * CVector(s,-s,0); poly.Vertices[2]= mat * CVector(s,s,0); poly.Vertices[3]= mat * CVector(-s,s,0); // clip this poly against all the other (ie not me) planes // This make this algo O(N2) but this is for debug.... for(uint k=0;k_Volume.size();k++) { if(j!=k) { poly.clip(&cluster->_Volume[k], 1); } } // count the number of vertices / triangles / lines to add if(poly.Vertices.size()>=3) { numTotalVertices+= (uint)poly.Vertices.size(); } } // **** count the number of portals vertices for(j=0;j_Portals.size();j++) { numTotalVertices+= (uint)cluster->_Portals[j]->_Poly.size(); } // **** Draw those cluster polygons, and portals // too big clusters won't be rendered if(numTotalVertices<=maxVertices) { uint iVert= 0; uint j; // build the cluster geometry clusterTriangles.setNumIndexes(maxVertices*3); clusterLines.setNumIndexes(maxVertices*2); // Locks CVertexBufferReadWrite vba; vb.lock (vba); CIndexBufferReadWrite ibaCT; clusterTriangles.lock (ibaCT); CIndexBufferReadWrite ibaCL; clusterLines.lock (ibaCL); uint numTriIndexes = 0; uint numLineIndexes = 0; for(j=0;j=3) { uint k; // add the vertices for(k=0;k_Portals.size();j++) { std::vector &portalVerts= cluster->_Portals[j]->_Poly; if(portalVerts.size()>=3) { uint k; // add the vertices for(k=0;kactiveVertexBuffer(vb); drv->activeIndexBuffer(clusterTriangles); drv->renderTriangles (clusterMat, 0, clusterTriangles.getNumIndexes()/3); drv->activeIndexBuffer(clusterLines); drv->renderLines (lineMat, 0, clusterLines.getNumIndexes()/2); drv->activeIndexBuffer(portalTriangles); drv->renderTriangles (portalMat, 0, portalTriangles.getNumIndexes()/3); drv->activeIndexBuffer(portalLines); drv->renderLines (lineMat, 0, portalLines.getNumIndexes()/2); } } } } // **** For all clusters, Draw the cluster name at center of the cluster if(txtCtx) { CComputedString computedStr; // bkup fontSize uint bkFontSize; CMatrix fontMatrix; bkFontSize= txtCtx->getFontSize(); // to be readable txtCtx->setFontSize(24); // the font matrix fontMatrix.setRot(drv->getViewMatrix().inverted()); fontMatrix.normalize(CMatrix::YZX); fontMatrix.scale(10); // parse all clusters for(i=0;i<_ClusterInstances.size();i++) { CCluster *cluster= _ClusterInstances[i]; if(cluster) { fontMatrix.setPos(cluster->_BBox.getCenter()); txtCtx->computeString(cluster->Name, computedStr); computedStr.render3D(*drv, fontMatrix); } } // restore fontsize txtCtx->setFontSize(bkFontSize); } } } // NL3D