# Home    # nevrax.com   
Nevrax
Nevrax.org
#News
#Mailing-list
#Documentation
#CVS
#Bugs
#License
Docs
 
Documentation  
Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages   Search  

clip_trav.cpp

Go to the documentation of this file.
00001 
00007 /* Copyright, 2000 Nevrax Ltd.
00008  *
00009  * This file is part of NEVRAX NEL.
00010  * NEVRAX NEL is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2, or (at your option)
00013  * any later version.
00014 
00015  * NEVRAX NEL is distributed in the hope that it will be useful, but
00016  * WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00018  * General Public License for more details.
00019 
00020  * You should have received a copy of the GNU General Public License
00021  * along with NEVRAX NEL; see the file COPYING. If not, write to the
00022  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00023  * MA 02111-1307, USA.
00024  */
00025 
00026 #include "std3d.h"
00027 
00028 #include "nel/misc/types_nl.h"
00029 #include "3d/clip_trav.h"
00030 #include "3d/hrc_trav.h"
00031 #include "3d/render_trav.h"
00032 #include "3d/anim_detail_trav.h"
00033 #include "3d/load_balancing_trav.h"
00034 #include "3d/cluster.h"
00035 #include "3d/scene_group.h"
00036 #include "3d/transform_shape.h"
00037 #include "3d/camera.h"
00038 #include "3d/quad_grid_clip_cluster.h"
00039 #include "3d/quad_grid_clip_manager.h"
00040 #include "3d/root_model.h"
00041 #include "nel/misc/hierarchical_timer.h"
00042 #include "3d/scene.h"
00043 #include "3d/skeleton_model.h"
00044 #include "3d/fast_floor.h"
00045 
00046 using namespace std;
00047 using namespace NLMISC;
00048 
00049 
00050 namespace       NL3D
00051 {
00052 
00053 
00054 // ***************************************************************************
00055 CClipTrav::CClipTrav() : ViewPyramid(6), WorldPyramid(6)
00056 {
00057         _VisibleList.reserve(1024);
00058         CurrentDate = 0;
00059         Accel.create (64, 16.0f);
00060 
00061         ForceNoFrustumClip= false;
00062         _QuadGridClipManager= NULL;
00063 
00064 
00065         HrcTrav= NULL;
00066         AnimDetailTrav= NULL;
00067         LoadBalancingTrav= NULL;
00068         LightTrav= NULL;
00069         RenderTrav = NULL;
00070 }
00071 
00072 // ***************************************************************************
00073 CClipTrav::~CClipTrav()
00074 {
00075 }
00076 
00077 // ***************************************************************************
00078 IObs* CClipTrav::createDefaultObs() const
00079 {
00080         return new CDefaultClipObs;
00081 }
00082 
00083 // ***************************************************************************
00084 bool CClipTrav::fullSearch (vector<CCluster*>& result, CInstanceGroup *pIG, CVector& pos)
00085 {
00086         uint32 i, j;
00087 
00088         for (i = 0; i < pIG->_ClusterInstances.size(); ++i)
00089         {
00090                 for (j = 0; j < pIG->_ClusterInstances[i]->Children.size(); ++j)
00091                 {
00092                         if (fullSearch (result, pIG->_ClusterInstances[i]->Children[j]->Group, pos))
00093                                 return true;
00094                 }
00095         }
00096 
00097         for (i = 0; i < pIG->_ClusterInstances.size(); ++i)
00098         {
00099                 if (pIG->_ClusterInstances[i]->isIn(pos))
00100                         result.push_back (pIG->_ClusterInstances[i]);
00101         }
00102         if (result.size() > 0)
00103                 return true;
00104         return false;
00105 }
00106 
00107 // ***************************************************************************
00108 void CClipTrav::traverse()
00109 {
00110         H_AUTO( NL3D_TravClip );
00111 
00112         // Increment the current date of the traversal
00113         ++CurrentDate;
00114         // Update Clip infos.
00115         ITravCameraScene::update();
00116 
00117         // Compute pyramid in view basis.
00118         CVector         pfoc(0,0,0);
00119         CVector         lb(Left,  Near, Bottom );
00120         CVector         lt(Left,  Near, Top    );
00121         CVector         rb(Right, Near, Bottom );
00122         CVector         rt(Right, Near, Top    );
00123 
00124         CVector         lbFar(Left,  Far, Bottom);
00125         CVector         ltFar(Left,  Far, Top   );
00126         CVector         rtFar(Right, Far, Top   );
00127 
00128         uint32 i, j;
00129 
00130         ViewPyramid[NL3D_CLIP_PLANE_NEAR].make(lt, lb, rt);
00131         ViewPyramid[NL3D_CLIP_PLANE_FAR].make(lbFar, ltFar, rtFar);
00132 
00133         ViewPyramid[NL3D_CLIP_PLANE_LEFT].make(pfoc, lt, lb);
00134         ViewPyramid[NL3D_CLIP_PLANE_TOP].make(pfoc, rt, lt);
00135         ViewPyramid[NL3D_CLIP_PLANE_RIGHT].make(pfoc, rb, rt);
00136         ViewPyramid[NL3D_CLIP_PLANE_BOTTOM].make(pfoc, lb, rb);
00137         
00138         // Compute pyramid in World basis.
00139         // The vector transformation M of a plane p is computed as p*M-1.
00140         // Here, ViewMatrix== CamMatrix-1. Hence the following formula.
00141         for (i = 0; i < 6; i++)
00142         {
00143                 WorldPyramid[i]= ViewPyramid[i]*ViewMatrix;
00144         }
00145 
00146         // bkup this pyramid (because this one may be modified by the cluster system).
00147         WorldFrustumPyramid= WorldPyramid;
00148 
00149 
00150         // update the QuadGridClipManager.
00151         if(_QuadGridClipManager)
00152         {
00153                 _QuadGridClipManager->updateClustersFromCamera(this, CamPos);
00154         }
00155 
00156         // Clear the traversals list.
00157         nlassert(AnimDetailTrav && LoadBalancingTrav && LightTrav && RenderTrav);
00158         AnimDetailTrav->clearVisibleList();
00159         LoadBalancingTrav->clearVisibleList();
00160         LightTrav->clearLightedList();
00161         RenderTrav->clearRenderList();
00162 
00163 
00164         /* For all objects marked visible in preceding render, reset Visible state here.
00165                 NB: must reset Visible State to false because sometimes ClipObs::traverse() are even not executed
00166                 (Cluster clip, QuadGridClipManager clip...).
00167                 And somes models read this Visible state. eg: Skins/StickedObjects test the Visible state of 
00168                 their _AncestorSkeletonModel.
00169         */
00170         for (i=0;i<_VisibleList.size();i++)
00171         {
00172                 // if the observer still exists (see ~IBaseClipObs())
00173                 if( _VisibleList[i] )
00174                 {
00175                         // disable his visibility.
00176                         _VisibleList[i]->Visible= false;
00177                         // let him know that it is no more in the list.
00178                         _VisibleList[i]->_IndexInVisibleList= -1;
00179                 }
00180         }
00181         // Clear The visible List.
00182         _VisibleList.clear();
00183 
00184 
00185         // Found where is the camera
00186         //========================
00187 
00188         // Found the cluster where the camera is
00189         static vector<CCluster*> vCluster;
00190 
00191         vCluster.clear();
00192 
00193         // In which cluster is the camera ?
00194         bool bInWorld = true;
00195         CQuadGrid<CCluster*>::CIterator itAcc;
00196         if (Camera->getClusterSystem() == (CInstanceGroup*)-1)
00197         {
00198                 if (fullSearch(vCluster, RootCluster->Group, CamPos))
00199                         bInWorld = false;
00200                 for (i = 0; i < vCluster.size(); ++i)
00201                         link(NULL, vCluster[i]);
00202         }
00203         else
00204         {
00205                 Accel.select (CamPos, CamPos);
00206                 itAcc = Accel.begin();
00207                 while (itAcc != Accel.end())
00208                 {
00209                         CCluster *pCluster = *itAcc;
00210                         if (pCluster->Group == Camera->getClusterSystem())
00211                         if (pCluster->isIn (CamPos))
00212                         {
00213                                 link (NULL, pCluster);
00214                                 vCluster.push_back (pCluster);
00215                                 bInWorld = false;
00216                         }
00217                         ++itAcc;
00218                 }
00219         }
00220 
00222         if (bInWorld)
00223         {
00224                 link (NULL, RootCluster);
00225                 vCluster.push_back (RootCluster);
00226         }
00227 
00228 
00229         // Manage Moving Objects
00230         //=====================
00231 
00232         // Unlink the moving objects from their clusters
00233         for (i = 0; i < HrcTrav->_MovingObjects.size(); ++i)
00234         {
00235                 CTransformShape *pTfmShp = dynamic_cast<CTransformShape*>(HrcTrav->_MovingObjects[i]);
00236                 if (pTfmShp == NULL)
00237                         continue;
00238 
00239                 static vector<IModel*> vModels;
00240                 vModels.clear();
00241                 IModel *pFather = getFirstParent (HrcTrav->_MovingObjects[i]);
00242                 while (pFather != NULL)
00243                 {
00244                         // Does the father is a cluster, or a CQuadGridClipCluster ??
00245                         if ( dynamic_cast<CCluster*>(pFather)!= NULL  ||  dynamic_cast<CQuadGridClipCluster*>(pFather)!=NULL )
00246                         {
00247                                 vModels.push_back (pFather);
00248                         }                       
00249                         pFather = getNextParent (HrcTrav->_MovingObjects[i]);
00250                 }
00251                 for (j = 0; j < vModels.size(); ++j)
00252                 {
00253                         unlink (vModels[j], HrcTrav->_MovingObjects[i]);
00254                 }
00255                 unlink (NULL, HrcTrav->_MovingObjects[i]);
00256         }
00257         
00258         // Affect the moving objects to their clusters
00259         for (i = 0; i < HrcTrav->_MovingObjects.size(); ++i)
00260         {
00261                 CTransformShape *pTfmShp = dynamic_cast<CTransformShape*>(HrcTrav->_MovingObjects[i]);
00262                 if (pTfmShp == NULL)
00263                         continue;
00264 
00265                 bool bInWorld = true;
00266                 CAABBox box;
00267                 pTfmShp->getAABBox (box);
00268                 // Transform the box in the world
00269                 CVector c = box.getCenter();
00270                 CVector p = box.getCenter()+box.getHalfSize();
00271                 const CMatrix &wm = pTfmShp->getWorldMatrix();
00272                 c = wm * c;
00273                 p = wm * p;
00274                 float s = (p - c).norm();
00275 
00276                 Accel.select (c+CVector(s,s,s), c+CVector(-s,-s,-s));
00277                 itAcc = Accel.begin();
00278                 while (itAcc != Accel.end())
00279                 {
00280                         CCluster *pCluster = *itAcc;
00281                         if (pCluster->Group == pTfmShp->getClusterSystem())
00282                         if (pCluster->isIn (c,s))
00283                         {
00284                                 link (pCluster, pTfmShp);
00285                                 bInWorld = false;
00286                         }
00287                         ++itAcc;
00288                 }
00289 
00290                 // Moving object in the world -> link to root or to the CQuadGridClipManager.
00291                 if (bInWorld)
00292                 {
00293                         if( _QuadGridClipManager && pTfmShp->isQuadGridClipEnabled() )
00294                         {
00295                                 // try to insert in the best cluster of the _QuadGridClipManager.
00296                                 if(!_QuadGridClipManager->linkModel(pTfmShp, this))
00297                                         // if fails, link to "root".
00298                                         link (RootCluster, pTfmShp);
00299                         }
00300                         else
00301                         {
00302                                 link (RootCluster, pTfmShp);
00303                         }
00304                 }
00305         }
00306 
00307         // Clip the graph.
00308         //=====================
00309 
00310         // Traverse the graph.
00311         if (Root)
00312                 Root->traverse (NULL);
00313 
00314 
00315         // Unlink the cluster where we are
00316         for (i = 0; i < vCluster.size(); ++i)
00317         {
00318                 unlink (NULL, vCluster[i]);
00319         }
00320 
00321 
00322         // Load Balance the Skeleton CLod state here. 
00323         // =========================
00324         /* Can't do it in LoadBalancingTrav because sons with _AncestorSkeletonModel!=NULL may be hiden if a skeleton
00325                 is displayed in CLod mode.
00326                 So must do it here, then clip all sons of AncestoreSkeletonModelGroup.
00327         */
00328         loadBalanceSkeletonCLod();
00329 
00330 
00331         // At the end of the clip traverse, must update clip for Objects which have a skeleton ancestor
00332         // =========================
00333         // those are linked to the SonsOfAncestorSkeletonModelGroup, so traverse it now.
00334         if (SonsOfAncestorSkeletonModelGroup)
00335                 SonsOfAncestorSkeletonModelGroup->getObs(ClipTravId)->traverse(NULL);
00336 
00337 
00338         // Update Here the Skin render Lists of All visible Skeletons
00339         // =========================
00340         /*
00341                 Done here, because AnimDetail and Render need correct lists. NB: important to do it 
00342                 before Render Traversal, because updateSkinRenderLists() may change the transparency flag!!
00343                 NB: can't do it in the clipObs of the skeleton since _DisplayLodCharacterFlag must be updated for this frame.
00344         */
00345         CScene::ItSkeletonModelList             itSkel;
00346         for(itSkel= Scene->getSkeletonModelListBegin(); itSkel!=Scene->getSkeletonModelListEnd(); itSkel++)
00347         {
00348                 CSkeletonModel  *sm= *itSkel;
00349                 // if visible
00350                 if(sm->isClipVisible())
00351                         sm->updateSkinRenderLists();
00352         }
00353 
00354 }
00355 
00356 
00357 // ***************************************************************************
00358 void CClipTrav::setHrcTrav (CHrcTrav* trav)
00359 {
00360         HrcTrav = trav;
00361 }
00362 
00363 // ***************************************************************************
00364 void CClipTrav::setAnimDetailTrav(CAnimDetailTrav *trav)
00365 {
00366         AnimDetailTrav= trav;
00367 }
00368 
00369 // ***************************************************************************
00370 void CClipTrav::setLoadBalancingTrav(CLoadBalancingTrav *trav)
00371 {
00372         LoadBalancingTrav= trav;
00373 }
00374 
00375 // ***************************************************************************
00376 void CClipTrav::setLightTrav (CLightTrav* trav)
00377 {
00378         LightTrav = trav;
00379 }
00380 
00381 // ***************************************************************************
00382 void CClipTrav::setRenderTrav (CRenderTrav* trav)
00383 {
00384         RenderTrav = trav;
00385 }
00386 
00387 // ***************************************************************************
00388 void CClipTrav::setQuadGridClipManager(CQuadGridClipManager *mgr)
00389 {
00390         _QuadGridClipManager= mgr;
00391 }
00392 
00393 // ***************************************************************************
00394 void CClipTrav::registerCluster (CCluster* pCluster)
00395 {
00396         pCluster->AccelIt = Accel.insert (pCluster->getBBox().getMin(), pCluster->getBBox().getMax(), pCluster);
00397 }
00398 
00399 // ***************************************************************************
00400 void CClipTrav::unregisterCluster (CCluster* pCluster)
00401 {
00402         Accel.selectAll();
00403         CQuadGrid<CCluster*>::CIterator itAcc = Accel.begin();
00404         while (itAcc != Accel.end())
00405         {
00406                 CCluster *pC = *itAcc;
00407                 if (pCluster == pC)
00408                 {
00409                         Accel.erase (itAcc);
00410                         break;
00411                 }
00412                 ++itAcc;
00413         }
00414 }
00415 
00416 
00417 // ***************************************************************************
00418 void CClipTrav::setSonsOfAncestorSkeletonModelGroup(CRootModel *m)
00419 {
00420         SonsOfAncestorSkeletonModelGroup= m;
00421 }
00422 
00423 
00424 // ***************************************************************************
00425 void CClipTrav::addVisibleObs(CTransformClipObs *obs)
00426 {
00427         obs->_IndexInVisibleList= _VisibleList.size();
00428         _VisibleList.push_back(obs);
00429 }
00430 
00431 
00432 // ***************************************************************************
00433 void CClipTrav::loadBalanceSkeletonCLod()
00434 {
00435         CScene::ItSkeletonModelList             itSkel;
00436         _TmpSortSkeletons.clear();
00437 
00438         // **** compute CLod priority of each skeleton,
00439         for(itSkel= Scene->getSkeletonModelListBegin(); itSkel!=Scene->getSkeletonModelListEnd(); itSkel++)
00440         {
00441                 CSkeletonModel  *sm= *itSkel;
00442                 float   pr= sm->computeDisplayLodCharacterPriority();
00443                 // If valid priority (CLOd enabled, and skeleton visible)
00444                 if(pr>0)
00445                 {
00446                         // if the priority is >1, then display as CLod
00447                         if(pr>1)
00448                                 sm->setDisplayLodCharacterFlag(true);
00449                         // else load balance.
00450                         else
00451                         {
00452                                 CSkeletonKey    key;
00453                                 // don't bother OptFastFloor precision. NB: 0<pr<=1 here.
00454                                 key.Priority= OptFastFloor(pr*0xFFFFFF00);
00455                                 key.SkeletonModel= sm;
00456                                 _TmpSortSkeletons.push_back(key);
00457                         }
00458                 }
00459         }
00460 
00461         // **** sort by priority in ascending order
00462         uint    nMaxSkelsInNotCLodForm= Scene->getMaxSkeletonsInNotCLodForm();
00463         // Optim: need it only if too many skels
00464         if(_TmpSortSkeletons.size()>nMaxSkelsInNotCLodForm)
00465         {
00466                 sort(_TmpSortSkeletons.begin(), _TmpSortSkeletons.end());
00467         }
00468 
00469         // **** set CLod flag 
00470         uint    n= min(nMaxSkelsInNotCLodForm, _TmpSortSkeletons.size());
00471         uint    i;
00472         // The lowest priority are displayed in std form
00473         for(i=0;i<n;i++)
00474         {
00475                 _TmpSortSkeletons[i].SkeletonModel->setDisplayLodCharacterFlag(false);
00476         }
00477         // the other are displayed in CLod form
00478         for(i=n;i<_TmpSortSkeletons.size();i++)
00479         {
00480                 _TmpSortSkeletons[i].SkeletonModel->setDisplayLodCharacterFlag(true);
00481         }
00482 
00483 }
00484 
00485 
00486 }