Ignore:
Timestamp:
09/28/06 17:49:37 (18 years ago)
Author:
gumbau
Message:

Updated modules to the new interface and the new simplification algorithm improvements.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • GTP/trunk/Lib/Geom/shared/GTGeometry/src/GeoLodManager.cpp

    r1309 r1526  
    1212#include "GeoLodManager.h" 
    1313#include "GeoLodObject.h" 
    14 #include <algorithm> 
    15 /* 
     14#include "VertexData.h" 
     15#include <ntls.h> 
     16#include <map> 
     17 
     18using namespace Geometry; 
     19 
     20//#define MINIMUM_VALID_LOD_SIMILARITY 0.1f 
     21 
     22 
    1623namespace Geometry 
    1724{ 
    18  
    19  
    20         class lodobj_idpos_node_t 
     25        class lodobj_node_t : public Moveable<lodobj_node_t> 
    2126        { 
    2227        public: 
    23                 lodobj_idpos_node_t(LodObject *o):lodobj(o),must_recalculate_distance(true),dist2cam(0.0f){} 
     28                lodobj_node_t(const std::string &nam, float dist, LodObject *o):dist2cam(dist),lodobj(o),name(nam){ must_recalculate_distance=false; to_update=0; master=NULL; lodfactor=o->GetCurrentLodFactor(); precalpos=-1; } 
     29                lodobj_node_t(const lodobj_node_t &n){ operator=(n); } 
     30                float dist2cam; 
    2431                LodObject *lodobj; 
    25                 float dist2cam; // used to index the lodobj in the other map 
    26                 bool operator < (const lodobj_idpos_node_t &o) const { return (lodobj->GetUniqueID()<o.lodobj->GetUniqueID()); } 
     32                bool must_recalculate_distance; 
     33                uint32 to_update; 
     34                bool operator < (const lodobj_node_t &o) const { return (dist2cam < o.dist2cam); } 
     35                void operator = (const lodobj_node_t &n){ dist2cam=n.dist2cam; lodobj=n.lodobj; must_recalculate_distance=n.must_recalculate_distance; master=n.master; lodfactor=n.lodfactor; precalpos=-1; name=n.name; } 
     36 
     37                lodobj_node_t * master; 
     38                VectorMap<uint32,lodobj_node_t*> disciples; 
     39                float lodfactor; // virtual lod factor (the lodfactor it seems, not its real internal lodfactor) 
     40                int precalpos; 
     41                std::string name; 
    2742        }; 
    28 }*/ 
    29  
    30 using namespace Geometry; 
    31  
    32 LodManager::LodManager(float near, float far, const Geometry::Vector3 &campos) 
    33 :targetFPS(30),camera_changed(true),camera_pos(campos), 
    34  near_range(near),far_range(far) 
    35 { 
    36         // make the lodobj_dists vector into a heap 
    37         make_heap(lodobj_dists.begin(),lodobj_dists.end()); 
    38 } 
    39  
    40 void Geometry::LodManager::AddLodObj(LodObject * o, const Geometry::Vector3 &p) 
    41 { 
    42         float dist = CalculateDistToCamera(p); 
    43         lodobj_dists.push_back(lodobj_dist_node_t(dist,o)); 
    44         push_heap(lodobj_dists.begin(),lodobj_dists.end()); 
    45 //      lodobj_dists[dist] = lodobj_dist_node_t(o); 
     43 
     44        class NodeContainer 
     45        { 
     46        public: 
     47                Vector<lodobj_node_t> lodobj_dists; 
     48                std::map<uint32,Geometry::Vector3> lodobj_pos; // map key: LodObject UniqueID for efficient ID-based finding 
     49                Vector3 camera_pos; 
     50 
     51                int num_lod_sim; 
     52 
     53                NodeContainer(const Geometry::Vector3 &campos) 
     54                        :camera_pos(campos){ 
     55                } 
     56 
     57                ~NodeContainer(void){ 
     58                        for (VectorMap<std::string,lodobj_node_t**>::Iterator it = precalculated_lods.Begin();  
     59                                                                                                                                  it != precalculated_lods.End(); it ++) 
     60                        { 
     61                                lodobj_node_t **nodes = *it; 
     62                                delete[] nodes; 
     63                        } 
     64                } 
     65 
     66                void RecalculateDist(lodobj_node_t & node){ 
     67                        std::map<uint32,Vector3>::iterator posit = lodobj_pos.find(node.lodobj->GetUniqueID()); 
     68                        assert(posit!=lodobj_pos.end()); 
     69                        const Vector3 & pos = posit->second; 
     70 
     71                        node.dist2cam = CalculateDistToCamera(pos); 
     72                } 
     73 
     74                float CalculateDistToCamera(const Geometry::Vector3 &p) const 
     75                { 
     76                        Geometry::Vector3 v = camera_pos - p; 
     77                        float distquad = v.length(); 
     78                        return distquad; 
     79                } 
     80 
     81                lodobj_node_t * & GetPrecalculatedLOD(const std::string &name, int ipos){ 
     82                        int foundpos = precalculated_lods.Find(name); 
     83                        if (foundpos==-1) 
     84                        { 
     85                                lodobj_node_t **new_precalculated_lods=new lodobj_node_t*[num_lod_sim+1]; // +1 is done to include the highest lod (1.0) 
     86                                for (int i=0; i<num_lod_sim+1; i++) 
     87                                        new_precalculated_lods[i]=NULL; 
     88                                precalculated_lods.Add(name) = new_precalculated_lods; 
     89                                return new_precalculated_lods[ipos]; 
     90                        } 
     91                        else 
     92                        { 
     93                                return precalculated_lods[foundpos][ipos]; 
     94                        } 
     95                } 
     96 
     97                uint32 lod2precalpos(Real lodfactor){  
     98                        return (uint32)(num_lod_sim*lodfactor);  
     99                } 
     100 
     101        private: 
     102                // the following is an array of precalculated lods 
     103                // for 10 precalculated lods each element is in order [0.1, 0.2, 0.3, 0.4, 0.5, ...] 
     104                // for 100 precalculated lods each element is in order [0.01, 0.02, 0.03, 0.04, 0.05, ...] 
     105                // the funcion lod2precalpos translates a LOD factor to a position in the array 
     106                VectorMap<std::string,lodobj_node_t**> precalculated_lods; 
     107 
     108        }; 
     109} 
     110 
     111LodManager::LodManager(Real near, Real far, const Geometry::Vector3 &campos, int numslots) 
     112:lasttime(0),camera_changed(true),node_added(false), 
     113 near_range(near),far_range(far), 
     114 always_calculate_lod(false),force_highest_lod(false) 
     115{ 
     116        lodobj_container=new NodeContainer(campos); 
     117        lodobj_container->num_lod_sim = numslots; 
     118} 
     119 
     120LodManager::~LodManager(void) 
     121{ 
     122        delete lodobj_container; 
     123//      delete[] precalculated_lods; 
     124} 
     125 
     126void Geometry::LodManager::AddLodObj(const std::string &name, LodObject * o, const Geometry::Vector3 &p) 
     127{ 
     128        float dist = lodobj_container->CalculateDistToCamera(p); 
     129        lodobj_node_t auxnode(name,dist,o); 
     130         
     131        lodobj_container->lodobj_dists.Add(auxnode); 
     132        Sort(lodobj_container->lodobj_dists); 
     133 
    46134        UpdateLODObjectPos(o,p); 
    47 } 
    48  
    49  
    50 void Geometry::LodManager::UpdateLOD(void) 
    51 { 
    52         if (!lodobj_dists.empty()) 
     135        node_added=true; 
     136} 
     137 
     138 
     139void Geometry::LodManager::UpdateLOD(uint32 currFPS, uint32 targetFPS) 
     140{ 
     141        if (!lodobj_container->lodobj_dists.IsEmpty()) 
    53142        { 
    54143                // update distances to the camera 
    55                 bool must_resort = false; 
    56                 for (std::vector<lodobj_dist_node_t>::iterator it=lodobj_dists.begin(); it!=lodobj_dists.end(); it++) 
    57                 {                        
    58                         lodobj_dist_node_t & node = *it; 
    59                         if (camera_changed || node.must_recalculate_distance) 
    60                         { 
    61                                 RecalculateDist(node); 
    62                                 must_resort=true; 
    63                         } 
    64                 } 
    65                 if (must_resort) 
    66                         sort_heap(lodobj_dists.begin(),lodobj_dists.end()); 
    67  
    68                 // select a tree to change its LOD 
    69         //      float random_dist = SelectRandomDistance(); 
    70         //      std::map<float,Geometry::lodobj_dist_node_t>::iterator nearest = lodobj_dists.upper_bound(random_dist); 
    71  
    72                 // the begining of the list is the greater element (greater dist)                
    73                 lodobj_dist_node_t & node = lodobj_dists.front(); 
     144                if (camera_changed || node_added) 
     145                { 
     146                        bool must_resort = false; 
     147                        for (Vector<lodobj_node_t>::Iterator it=lodobj_container->lodobj_dists.Begin();  
     148                                                                                                 it!=lodobj_container->lodobj_dists.End();  
     149                                                                                                 it++) 
     150                        {                        
     151                                lodobj_node_t & node = *it; 
     152                                if (node.must_recalculate_distance || camera_changed || node_added) 
     153                                { 
     154                                        lodobj_container->RecalculateDist(node); 
     155                                        must_resort=true; 
     156                                } 
     157                        } 
     158/*                      if (must_resort) 
     159                                Sort(lodobj_container->lodobj_dists);*/ 
     160                } 
     161 
     162                // the end of the list is the greater element (greater dist)     
     163/*              if (currFPS < targetFPS - 5) 
     164                { 
     165                        Vector<lodobj_node_t>::Iterator selnode; 
     166                        for (selnode=lodobj_container->lodobj_dists.End()-1; selnode!=lodobj_container->lodobj_dists.Begin()-1; selnode--) 
     167                        {                        
     168                        // NO HAY QUE USAR CURRENT LOD FACTOR SINO lodobj_container->lodobj_lodfactor 
     169                                if (selnode->lodobj->GetCurrentLodFactor()>0.00001f) 
     170                                { 
     171                                        if (selnode->to_update==0) 
     172                                                break; 
     173                                        else 
     174                                                selnode->to_update--; 
     175                                } 
     176                        } 
     177 
     178                        if (selnode!=lodobj_container->lodobj_dists.Begin()-1) 
     179                        { 
     180                                // EL DECREMENTO O EL NUMERO DE DECREMENTOS TIENE QUE VENIR EN FUNCION DE LA DIFERENCIA DE FPS 
     181                                // NO HAY QUE USAR CURRENT LOD FACTOR SINO lodobj_container->lodobj_lodfactor 
     182                                selnode->lodobj->GoToLod(selnode->lodobj->GetCurrentLodFactor()-0.02f);  
     183                                selnode->to_update=10; // ESTO DEBE ASIGNARSE BASADO EN LA DISTANCIA A LA CAMARA! 
     184                        } 
     185                } 
     186                if (currFPS > targetFPS + 5) 
     187                { 
     188                        Vector<lodobj_node_t>::Iterator selnode; 
     189                        for (selnode=lodobj_container->lodobj_dists.Begin(); selnode!=lodobj_container->lodobj_dists.End(); selnode++) 
     190                        {                        
     191                        // NO HAY QUE USAR CURRENT LOD FACTOR SINO lodobj_container->lodobj_lodfactor 
     192                                if (selnode->lodobj->GetCurrentLodFactor()<0.99999f) 
     193                                { 
     194                                        if (selnode->to_update==0) 
     195                                                break; 
     196                                        else 
     197                                                selnode->to_update--; 
     198                                } 
     199                        } 
     200 
     201                        if (selnode!=lodobj_container->lodobj_dists.End()) 
     202                        { 
     203                        // NO HAY QUE USAR CURRENT LOD FACTOR SINO lodobj_container->lodobj_lodfactor 
     204                                selnode->lodobj->GoToLod(selnode->lodobj->GetCurrentLodFactor()+0.02f); 
     205                                selnode->to_update=10; // ESTO DEBE ASIGNARSE BASADO EN LA DISTANCIA A LA CAMARA! 
     206                        } 
     207                }*/ 
     208 
     209                if (camera_changed) 
     210                { 
     211                        // por ahora solo sacar el lod basado en la camara 
     212                        for (Vector<lodobj_node_t>::Iterator it = lodobj_container->lodobj_dists.Begin();  
     213                                                                                                 it != lodobj_container->lodobj_dists.End();  it ++) 
     214                        { 
     215                                float lodfactor = - ((it->dist2cam - near_range) / (far_range - near_range)); 
     216                                if (lodfactor < 0.0f) 
     217                                        lodfactor = 0.0f; 
     218                                if (lodfactor > 1.0f) 
     219                                        lodfactor = 1.0f; 
     220 
     221                                if (force_highest_lod) 
     222                                        lodfactor = 1.0f; 
     223 
     224                                ChangeLOD(it,lodfactor); 
     225                        } 
     226                }                                                           
    74227        } 
    75228        camera_changed=false; 
    76 } 
    77  
    78 void Geometry::LodManager::RecalculateDist(lodobj_dist_node_t & node) 
    79 { 
    80         std::map<uint32,Vector3>::iterator posit = lodobj_pos.find(node.lodobj->GetUniqueID()); 
    81         assert(posit!=lodobj_pos.end()); 
    82         const Vector3 & pos = posit->second; 
    83  
    84         node.dist2cam = CalculateDistToCamera(pos); 
    85 } 
    86  
     229        node_added=false; 
     230} 
     231 
     232void Geometry::LodManager::ChangeLOD(lodobj_node_t *lodobjnode, Real lodfactor) 
     233{ 
     234        LodObject *lodobj = lodobjnode->lodobj; 
     235 
     236        if (always_calculate_lod) 
     237        { 
     238                lodobj->GoToLod(lodfactor); 
     239                return; 
     240        } 
     241         
     242        // if the lodfactor is exactly 1.0 its level of detail must be always regenerated (for closeups) 
     243        if (lodfactor<1.0f) 
     244        { 
     245                // if the desired lod is very similar to the previous one, 
     246                // then there is no need to change the level of detail at all 
     247//              float sim = fabsf(lodfactor - lodobjnode->lodfactor); 
     248//              if (sim <= MINIMUM_VALID_LOD_SIMILARITY) 
     249//                      return; // do not change anything if the lod is very similar! 
     250                int desiredpos = lodobj_container->lod2precalpos(lodfactor); 
     251                int mypos = lodobj_container->lod2precalpos(lodobjnode->lodfactor); 
     252                if (mypos==desiredpos) 
     253                        return; 
     254        } 
     255 
     256        lodobj_node_t *found_node = FindMostSimilarRealLOD(lodobjnode->name,lodfactor); 
     257 
     258        if (found_node && found_node->lodobj->GetUniqueID()!=lodobj->GetUniqueID()) 
     259        { 
     260                // DEBUG 
     261                assert(found_node->master==NULL); 
     262 
     263//              float sim = fabsf(lodfactor - found_node->lodfactor); 
     264//              if (sim <= MINIMUM_VALID_LOD_SIMILARITY) 
     265                int desiredpos = lodobj_container->lod2precalpos(lodfactor); 
     266                int foundpos = lodobj_container->lod2precalpos(found_node->lodfactor); 
     267                if (foundpos==desiredpos) 
     268                { 
     269                        lodobj->GetIndexDataInterface()->BorrowIndexData(found_node->lodobj->GetIndexDataInterface()); 
     270                        MakeDiscipleOf(found_node,lodobjnode); 
     271                } 
     272                else 
     273                        ReallyGoToLOD(lodobjnode,lodfactor); 
     274        } 
     275        else 
     276                ReallyGoToLOD(lodobjnode,lodfactor); 
     277 
     278        lodobjnode->lodfactor = lodfactor; 
     279} 
     280 
     281void Geometry::LodManager::DeleteMeFromMyMastersDiscipleList(lodobj_node_t *lodobjnode) 
     282{ 
     283        // if I have a master... 
     284        if (lodobjnode->master) 
     285                lodobjnode->master->disciples.RemoveKey(lodobjnode->lodobj->GetUniqueID());      
     286} 
     287 
     288 
     289void Geometry::LodManager::MakeIndependent(lodobj_node_t *lodobjnode) 
     290{ 
     291        DeleteMeFromMyMastersDiscipleList(lodobjnode); 
     292 
     293        // next, delete my master 
     294        lodobjnode->master=NULL; 
     295} 
     296 
     297void Geometry::LodManager::MakeDiscipleOf(lodobj_node_t *master_node, lodobj_node_t *disciple_node) 
     298{ 
     299        ChangeMaster(disciple_node, master_node); 
     300 
     301        // delete my disciples 
     302        disciple_node->disciples.Clear(); 
     303 
     304        // first remove me from my master's disciple list 
     305        DeleteMeFromMyMastersDiscipleList(disciple_node); 
     306 
     307        master_node->disciples.GetAdd(disciple_node->lodobj->GetUniqueID()) = disciple_node; 
     308 
     309        // set master 
     310        disciple_node->master = master_node; 
     311 
     312        // no one must take me as a master! 
     313        if (disciple_node->precalpos!=-1) 
     314        {                
     315//              lodobj_container->precalculated_lods[disciple_node->precalpos] = NULL; 
     316                lodobj_container->GetPrecalculatedLOD(master_node->name,disciple_node->precalpos) = NULL; 
     317                disciple_node->precalpos = -1; 
     318        } 
     319} 
     320 
     321void Geometry::LodManager::ChangeMaster(lodobj_node_t *lodobj, lodobj_node_t *newmaster) 
     322{ 
     323        // delete me from my disciples' master list 
     324        for (VectorMap<uint32,lodobj_node_t*>::Iterator it = lodobj->disciples.Begin(); it != lodobj->disciples.End(); it++) 
     325        { 
     326                lodobj_node_t * auxnode = *it; 
     327                assert(auxnode->master->lodobj->GetUniqueID() == lodobj->lodobj->GetUniqueID()); 
     328//              auxnode->master = NULL; 
     329                // chanbge the master to the new one 
     330                auxnode->master = newmaster; 
     331 
     332                // add the new disciple to the new master 
     333                if (newmaster) 
     334                        newmaster->disciples.GetAdd(auxnode->lodobj->GetUniqueID()) = auxnode; 
     335        }        
     336} 
     337 
     338 
     339void Geometry::LodManager::UpdateDisciples(lodobj_node_t *master_node) 
     340{ 
     341        for (VectorMap<uint32,lodobj_node_t*>::Iterator it= master_node->disciples.Begin(); it!= master_node->disciples.End(); it++) 
     342        { 
     343                lodobj_node_t *disciple_node = *it; 
     344                disciple_node->lodobj->GetIndexDataInterface()->BorrowIndexData(master_node->lodobj->GetIndexDataInterface()); 
     345                disciple_node->lodfactor = master_node->lodobj->GetCurrentLodFactor(); // we can use currentlodfactor here because the master is supposed to be at its REAL level of detail 
     346        } 
     347} 
     348 
     349void Geometry::LodManager::ReallyGoToLOD(lodobj_node_t *lodobjnode, Real lodfactor) 
     350{ 
     351        lodobjnode->lodobj->GoToLod(lodfactor); 
     352 
     353        MakeIndependent(lodobjnode); 
     354        UpdateDisciples(lodobjnode); 
     355 
     356        // store the precalculated lod in the table 
     357        int i = lodobj_container->lod2precalpos(lodfactor); 
     358 
     359        assert(i>=0 && i<=lodobj_container->num_lod_sim); // <= por lo del +1 
     360 
     361        if (lodobjnode->precalpos != -1) 
     362                //lodobj_container->precalculated_lods[lodobjnode->precalpos] = NULL; 
     363                lodobj_container->GetPrecalculatedLOD(lodobjnode->name,lodobjnode->precalpos) = NULL; 
     364 
     365//      lodobj_container->precalculated_lods[i] = lodobjnode; 
     366        lodobj_container->GetPrecalculatedLOD(lodobjnode->name,i) = lodobjnode; 
     367 
     368        lodobjnode->precalpos = i; 
     369} 
     370 
     371 
     372lodobj_node_t * Geometry::LodManager::FindMostSimilarRealLOD(const std::string &name, Real desired_lod) 
     373{ 
     374        uint32 i = lodobj_container->lod2precalpos(desired_lod); 
     375        assert(i>=0 && i<=lodobj_container->num_lod_sim); // <= por lo del +1 
     376//      lodobj_node_t *obj = lodobj_container->precalculated_lods[i]; 
     377        lodobj_node_t *obj = lodobj_container->GetPrecalculatedLOD(name,i); 
     378 
     379        return obj; 
     380} 
    87381 
    88382void Geometry::LodManager::UpdateCamera(const Geometry::Vector3 &p) 
    89383{ 
    90         camera_pos = p; 
     384        lodobj_container->camera_pos = p; 
    91385        camera_changed = true; 
    92386} 
     
    94388void Geometry::LodManager::UpdateLODObjectPos(LodObject *o, const Geometry::Vector3 &p) 
    95389{ 
    96         lodobj_pos[o->GetUniqueID()] = p; 
    97 } 
    98  
    99  
    100 float Geometry::LodManager::CalculateDistToCamera(const Geometry::Vector3 &p) const 
    101 { 
    102         return camera_pos.dotProduct(p); 
    103 } 
     390        lodobj_container->lodobj_pos[o->GetUniqueID()] = p; 
     391} 
     392 
    104393 
    105394float Geometry::LodManager::SelectRandomDistance(void) const 
Note: See TracChangeset for help on using the changeset viewer.