root/OpenSceneGraph/trunk/src/osgPlugins/txp/trpage_managers.cpp @ 13041

Revision 13041, 33.3 kB (checked in by robert, 3 years ago)

Ran script to remove trailing spaces and tabs

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/* ************************
2   Copyright Terrain Experts Inc.
3   Terrain Experts Inc (TERREX) reserves all rights to this source code
4   unless otherwise specified in writing by the President of TERREX.
5   This copyright may be updated in the future, in which case that version
6   supercedes this one.
7   -------------------
8   Terrex Experts Inc.
9   4400 East Broadway #314
10   Tucson, AZ  85711
11   info@terrex.com
12   Tel: (520) 323-7990
13   ************************
14   */
15
16#include <stdlib.h>
17#include <stdio.h>
18#include <string.h>
19#include <stdexcept>
20
21#include <trpage_sys.h>
22#include <trpage_geom.h>
23#include <trpage_read.h>
24#include <trpage_print.h>
25#include <trpage_managers.h>
26
27/* Managed Tile class.
28    Check the header file for details.
29 */
30
31trpgManagedTile::trpgManagedTile()
32{
33    isLoaded = false;
34    location.x = location.y = -1;
35    location.lod = -1;
36    localData = NULL;
37}
38
39void trpgManagedTile::Reset()
40{
41    // Null out the local material data
42    for (unsigned int i=0;i<localMatData.size();i++)
43        localMatData[i] = NULL;
44    groupIDs.resize(0);
45
46    isLoaded = false;
47    location.x = location.y = -1;
48    location.lod = -1;
49    localData = NULL;
50
51    childLocationInfo.clear();
52
53}
54
55bool trpgManagedTile::ParseTileHeader(trpgReadBuffer &buf)
56{
57    isLoaded = false;
58    if (!tileHead.Read(buf))
59        return false;
60
61    int numLoc;
62    tileHead.GetNumLocalMaterial(numLoc);
63    localMatData.resize(numLoc);
64
65    // The tile considers itself loaded with just
66    //  the header.  This isn't true as far as the paging
67    //  manager is concerned.
68    isLoaded = true;
69    return true;
70}
71
72bool trpgManagedTile::IsLoaded()
73{
74    return isLoaded;
75}
76
77bool trpgManagedTile::SetTileLoc(int inX,int inY,int inLod)
78{
79    location.x = inX;
80    location.y = inY;
81    if (inLod < 0)
82        return false;
83    location.lod = inLod;
84
85    return true;
86}
87
88bool trpgManagedTile::GetTileLoc(int &retx,int &rety,int &retLod) const
89{
90    retx = location.x;  rety = location.y;  retLod = location.lod;
91
92    return true;
93}
94
95void trpgManagedTile::SetTileAddress(const trpgwAppAddress& gAddr)
96{
97    location.addr = gAddr;
98}
99void trpgManagedTile::SetTileAddress(int32 file, int32 offset)
100{
101    location.addr.file = file;
102    location.addr.offset = offset;
103}
104const trpgwAppAddress& trpgManagedTile::GetTileAddress() const
105{
106    return location.addr;
107}
108bool trpgManagedTile::SetChildLocationInfo(int childIdx, int x, int y, const trpgwAppAddress& addr)
109{
110    if(childIdx < 0)
111        throw std::invalid_argument(
112                "trpgManagedTile::SetChildLocationInfo(): index argument out of bound.");
113
114    int size = childLocationInfo.size();
115    if(childIdx < size)
116        childLocationInfo[childIdx] = TileLocationInfo(x, y, location.lod+1, addr);
117    else if(childIdx == size)
118        childLocationInfo.push_back(TileLocationInfo(x, y, location.lod+1, addr));
119    else
120    {
121        childLocationInfo.resize(childIdx+1);
122        childLocationInfo[childIdx] = TileLocationInfo(x, y, location.lod+1, addr);
123    }
124
125    return true;
126}
127bool trpgManagedTile::SetChildLocationInfo(int childIdx, const TileLocationInfo& info)
128{
129    if(childIdx < 0)
130        throw std::invalid_argument(
131                "trpgManagedTile::SetChildLocationInfo(): index argument out of bound.");
132
133    int size = childLocationInfo.size();
134    if(childIdx < size)
135        childLocationInfo[childIdx] = info;
136    else if(childIdx == size)
137        childLocationInfo.push_back(info);
138    else
139    {
140        childLocationInfo.resize(childIdx+1);
141        childLocationInfo[childIdx] = info;
142    }
143
144    return true;
145}
146const TileLocationInfo& trpgManagedTile::GetChildLocationInfo(int childIdx) const
147{
148    if(childIdx < 0 || childIdx >= (int)childLocationInfo.size())
149        throw std::invalid_argument(
150                "trpgManagedTile::GetChildLocationInfo(): index argument out of bound.");
151
152
153    return childLocationInfo[childIdx];
154}
155
156bool trpgManagedTile::GetChildTileLoc(int childIdx, int &x,int &y,int &lod) const
157{
158    if(childIdx < 0 || childIdx >= (int)childLocationInfo.size())
159        throw std::invalid_argument(
160                "trpgManagedTile::GetChildTileLoc(): index argument out of bound.");
161    TileLocationInfo const& info = childLocationInfo[childIdx];
162
163    x = info.x;
164    y = info.y;
165    lod = info.lod;
166
167    return true;
168}
169
170const trpgwAppAddress& trpgManagedTile::GetChildTileAddress(int childIdx) const
171{
172    if(childIdx < 0 || childIdx >= (int)childLocationInfo.size())
173        throw std::invalid_argument(
174                "trpgManagedTile::GetChildTileAddress(): index argument out of bound.");
175    return childLocationInfo[childIdx].addr;
176}
177
178const trpgTileHeader *trpgManagedTile::GetTileHead()
179{
180    return &tileHead;
181}
182
183const std::vector<trpgLocalMaterial> *trpgManagedTile::GetLocMatList() const
184{
185    return tileHead.GetLocalMaterialList();
186}
187
188const trpgLocalMaterial *trpgManagedTile::GetLocMaterial(int id) const
189{
190    const std::vector<trpgLocalMaterial> *matList;
191    matList = tileHead.GetLocalMaterialList();
192
193    if (id <0 || id >= (int)matList->size())
194        return NULL;
195
196    return &(*matList)[id];
197}
198
199void trpgManagedTile::SetLocalData(void *inData)
200{
201    localData = inData;
202}
203
204void *trpgManagedTile::GetLocalData() const
205{
206    return localData;
207}
208
209bool trpgManagedTile::SetMatData(int id,void *info)
210{
211    if (id < 0 || id >= (int)localMatData.size())
212        return false;
213
214    localMatData[id] = info;
215
216    return true;
217}
218
219void *trpgManagedTile::GetMatData(int id) const
220{
221    if (id < 0 || id >= (int)localMatData.size())
222        return NULL;
223
224    return localMatData[id];
225}
226
227void trpgManagedTile::AddGroupID(int id)
228{
229    groupIDs.push_back(id);
230}
231
232const std::vector<int> *trpgManagedTile::GetGroupIDs() const
233{
234    return &groupIDs;
235}
236
237void trpgManagedTile::Print(trpgPrintBuffer &buf)
238{
239    char line[1024];
240    sprintf(line,"x = %d, y = %d, lod = %d",location.x, location.y, location.lod);  buf.prnLine(line);
241    // Note: Should print the rest too, probably.
242}
243
244/*  Page Manager LOD Page Info class.
245    Used by the page manager to keep track of paging information
246    for a single terrain LOD.  See the header file for details.
247*/
248
249trpgPageManager::LodPageInfo::LodPageInfo()
250{
251    valid = false;
252    pageDist = 0.0;
253    cell.x = cell.y = -100;
254}
255
256trpgPageManager::LodPageInfo::~LodPageInfo()
257{
258    Clean();
259}
260
261void trpgPageManager::LodPageInfo::Clean()
262{
263    // Clean up managed tile structures
264    unsigned int i;
265    for (i=0;i<load.size();i++)
266        if (load[i])
267            delete load[i];
268    load.resize(0);
269    for (i=0;i<unload.size();i++)
270        if (unload[i])
271            delete unload[i];
272    unload.resize(0);
273    for (i=0;i<current.size();i++)
274        if (current[i])
275            delete current[i];
276    current.resize(0);
277    for (i=0;i<freeList.size();i++)
278        delete freeList[i];
279    freeList.resize(0);
280    activeLoad = false;
281    activeUnload = false;
282}
283
284bool trpgPageManager::LodPageInfo::Init(trpgr_Archive *archive, int myLod, double scale, int freeListDivider)
285{
286    Clean();
287
288    lod = myLod;
289    // In theory we could have a negative scale, but I don't
290    //  really want to deal with that.
291    if (scale < 0)  scale = 0.0;
292
293    tileTable = archive->GetTileTable();
294
295    // Need some size and shape info about our terrain LOD
296    const trpgHeader *head = archive->GetHeader();
297    head->GetTileSize(lod,cellSize);
298    head->GetLodRange(lod,pageDist);
299    head->GetLodSize(lod,lodSize);
300    pageDist *= scale;
301
302    head->GetVersion(majorVersion, minorVersion);
303
304
305    // Area of interest size (in cells)
306    aoiSize.x = (int)(pageDist/cellSize.x);
307    aoiSize.y = (int)(pageDist/cellSize.y);
308
309    /* Make a guess as to how many tiles we might have loaded
310       in at any given time.  Give ourselves 15% extra room.
311       From the area of interest in cells, we can guess the max
312       number of tiles (aka cells) we'll have loaded in at once.
313       Note that the AOI size is only ahead, so it must be doubled.
314
315       Version 2.1 now support variable lods, it might be overkill to
316       allocate a free list by supposing that the tiles exist.
317       So only for version 2.1 an over we will use the divider to allocate less
318    */
319    maxNumTiles = (int)(1.15*(2*aoiSize.x+1)*(2*aoiSize.y+1));
320    if(majorVersion == 2 && minorVersion >= 1)
321        maxNumTiles = (int)(1.15*(2*aoiSize.x+1)*(2*aoiSize.y+1)/freeListDivider);
322    else
323        maxNumTiles = (int)(1.15*(2*aoiSize.x+1)*(2*aoiSize.y+1));
324
325
326
327
328    // Allocate 'em
329    for (int i=0;i<maxNumTiles;i++) {
330        trpgManagedTile *tile = new trpgManagedTile();
331        freeList.push_back(tile);
332    }
333
334    // We still don't have a position yet
335    valid = true;
336
337    return true;
338}
339
340bool trpgPageManager::LodPageInfo::SetLocation(trpg2dPoint &loc)
341{
342    // Calculate the cell this falls into
343    trpg2iPoint newCell;
344    newCell.x = (int)(loc.x/cellSize.x);
345    newCell.y = (int)(loc.y/cellSize.y);
346
347    // Snap to the database border
348    if (newCell.x < 0)  newCell.x = 0;
349    if (newCell.y < 0)  newCell.y = 0;
350    if (newCell.x >= lodSize.x)  newCell.x = lodSize.x-1;
351    if (newCell.y >= lodSize.y)  newCell.y = lodSize.y-1;
352
353    // Nothing to page.  Done.
354    if (newCell.x == cell.x && newCell.y == cell.y)
355        return false;
356
357    // Cell has changed.  Update.
358    cell = newCell;
359
360    Update();
361
362    return true;
363}
364
365trpgManagedTile *trpgPageManager::LodPageInfo::GetNextLoad()
366{
367    // Can only load one tile at a time
368    if (activeLoad)
369        return NULL;
370
371    // Clear any NULLs at the beginning
372    while (load.size() && !load[0])
373        load.pop_front();
374
375    if (load.size() > 0) {
376        activeLoad = true;
377        return load[0];
378    }
379
380    return NULL;
381}
382
383void trpgPageManager::LodPageInfo::AckLoad()
384{
385    if (activeLoad) {
386        current.push_back(load[0]);
387        load.pop_front();
388    }
389    activeLoad = false;
390}
391
392trpgManagedTile *trpgPageManager::LodPageInfo::GetNextUnload()
393{
394    // Can only unload one tile at a time
395    if (activeUnload)
396        return NULL;
397
398    // Clear any NULLs at the beginning
399    while (unload.size() && !unload[0])
400        unload.pop_front();
401
402    if (unload.size() > 0) {
403        activeUnload = true;
404        return unload[0];
405    }
406
407    return NULL;
408}
409
410void trpgPageManager::LodPageInfo::AckUnload()
411{
412    if (activeUnload) {
413        trpgManagedTile *tile = unload[0];
414        tile->Reset();
415        freeList.push_back(tile);
416        unload.pop_front();
417    }
418    activeUnload = false;
419}
420
421bool trpgPageManager::LodPageInfo::isWithin(trpgManagedTile *tile,trpg2iPoint &sw,trpg2iPoint &ne)
422{
423    int tileX,tileY,tileLod;
424    tile->GetTileLoc(tileX,tileY,tileLod);
425    if (tileX >= sw.x &&
426        tileX <= ne.x &&
427        tileY >= sw.y &&
428        tileY <= ne.y)
429        return true;
430    else
431        return false;
432}
433
434bool trpgPageManager::LodPageInfo::Stop()
435{
436    // Empty the load list
437    unsigned int i;
438    for (i=0;i<load.size();i++)
439        freeList.push_back(load[i]);
440    load.resize(0);
441
442    // Move the current tiles to the unload list
443    for (i=0;i<current.size();i++)
444        if (current[i])
445            unload.push_back(current[i]);
446    current.resize(0);
447
448    return (unload.size() > 0);
449}
450void trpgPageManager::LodPageInfo::AddChildrenToLoadList(std::vector<trpgManagedTile*>& parentList)
451{
452    if(parentList.size() == 0)
453        return;
454
455    // Area coverage, in cell unit
456    trpg2iPoint sw,ne;
457    sw.x = cell.x - aoiSize.x;
458    sw.y = cell.y - aoiSize.y;
459    ne.x = cell.x + aoiSize.x;
460    ne.y = cell.y + aoiSize.y;
461    sw.x = MAX(0,sw.x);
462    sw.y = MAX(0,sw.y);
463    ne.x = MIN(lodSize.x-1,ne.x);
464    ne.y = MIN(lodSize.y-1,ne.y);
465
466    int dx = ne.x - sw.x +1;
467    int dy = ne.y - sw.y +1;
468
469    // Mark the one that are already there
470    tmpCurrent.resize(dx*dy);
471    std::fill(tmpCurrent.begin(), tmpCurrent.end(), false);
472    for (unsigned int i = 0; i<current.size(); i++) {
473        trpgManagedTile *tile = current[i];
474        if (tile) {
475            int tileX,tileY,tileLod;
476            tile->GetTileLoc(tileX,tileY,tileLod);
477            tmpCurrent[(tileY-sw.y)*dx + (tileX-sw.x)] = true;
478        }
479    }
480    for (unsigned int i=0;i<load.size();i++) {
481        trpgManagedTile *tile = load[i];
482        if (tile) {
483            int tileX,tileY,tileLod;
484            tile->GetTileLoc(tileX,tileY,tileLod);
485            tmpCurrent[(tileY-sw.y)*dx + (tileX-sw.x)] = true;
486        }
487    }
488
489    for(unsigned int parentIdx = 0; parentIdx < parentList.size(); ++parentIdx) {
490
491        trpgManagedTile* parentTile = parentList[parentIdx];
492        unsigned int nbChildren = parentTile->GetNbChildren();
493
494        for(unsigned int childIdx = 0; childIdx < nbChildren; ++childIdx) {
495
496            const TileLocationInfo& childLoc = parentTile->GetChildLocationInfo(childIdx);
497
498            // a sanity check: if the lod is not the same then this
499            // parent is not at the right place
500            if(childLoc.lod != lod)
501                break;
502
503            // Make sure it is within
504            if (childLoc.x >= sw.x &&
505                childLoc.x <= ne.x &&
506                childLoc.y >= sw.y &&
507                childLoc.y <= ne.y)   {
508
509                // Is it alread there ?
510                if(!tmpCurrent[(childLoc.y - sw.y)*dx + (childLoc.x - sw.x)]) {
511
512                    // Not there, add it
513                    AddToLoadList(childLoc.x, childLoc.y, childLoc.addr);
514                }
515            }
516        }
517    }
518}
519
520bool trpgPageManager::LodPageInfo::AddToLoadList(int x, int y, const trpgwAppAddress& addr)
521{
522    trpg2iPoint sw,ne;
523
524    // Figure out the lower left and upper right corners
525    //  in cell coordinates
526    sw.x = cell.x - aoiSize.x;
527    sw.y = cell.y - aoiSize.y;
528    ne.x = cell.x + aoiSize.x;
529    ne.y = cell.y + aoiSize.y;
530    sw.x = MAX(0,sw.x);
531    sw.y = MAX(0,sw.y);
532    ne.x = MIN(lodSize.x-1,ne.x);
533    ne.y = MIN(lodSize.y-1,ne.y);
534
535    if (x >= sw.x &&
536        x <= ne.x &&
537        y >= sw.y &&
538        y <= ne.y)   {
539
540        trpgManagedTile *tile = 0;
541        if(freeList.size() > 0){
542
543            tile = freeList[0];
544            freeList.pop_front();
545        }
546        else
547            tile = new trpgManagedTile();
548        tile->SetTileLoc(x, y, lod);
549        tile->SetTileAddress(addr);
550        load.push_back(tile);
551
552        return true;
553    }
554    else
555        return false;
556}
557
558/* Update does the major work of figuring out what to load and
559   what to unload.
560*/
561
562void trpgPageManager::LodPageInfo::Update()
563{
564    trpg2iPoint sw,ne;
565
566    // Figure out the lower left and upper right corners
567    //  in cell coordinates
568    sw.x = cell.x - aoiSize.x;  sw.y = cell.y - aoiSize.y;
569    ne.x = cell.x + aoiSize.x;  ne.y = cell.y + aoiSize.y;
570    sw.x = MAX(0,sw.x);            sw.y = MAX(0,sw.y);
571    ne.x = MIN(lodSize.x-1,ne.x);   ne.y = MIN(lodSize.y-1,ne.y);
572
573    /* Load list -
574       Some of the tiles we're supposed to load may now be
575       out of range.  Take them off the load list.
576    */
577    unsigned int i;
578    for (i=0;i<load.size();i++) {
579        if (load[i] && !isWithin(load[i],sw,ne)) {
580            freeList.push_back(load[i]);
581            load[i] = NULL;
582        }
583    }
584
585    /* Unload list -
586       Some of the tiles we were planning on unloading may now
587       be in view again.  Move them back to current.
588    */
589    for (i=0;i<unload.size();i++) {
590        if (unload[i] && isWithin(unload[i],sw,ne)) {
591            current.push_back(unload[i]);
592            unload[i] = NULL;
593        }
594    }
595
596    /* Current list -
597       We need to figure out a few things here.
598       1) What's in the current list that should be paged out.
599       2) What's already paged, sorted into tmpCurrent.
600       3) What's missing from tmpCurrent and should be paged in.
601    */
602
603    // Look for tiles to page out
604    // Move them to the unload list
605    for (i=0;i<current.size();i++) {
606        if (current[i] && !isWithin(current[i],sw,ne)) {
607            unload.push_back(current[i]);
608            current[i] = NULL;
609        }
610    }
611    // Clean the NULLs out of the current list
612    int curPos = 0;
613    for (i=0;i<current.size();i++) {
614        if (current[i]) {
615            current[curPos] = current[i];
616            curPos++;
617        }
618    }
619    current.resize(curPos);
620
621    bool doUpdate = true;
622    if(majorVersion == 2 && minorVersion >= 1)
623    {
624        // Version 2.1, we update only lod 0 since the tile table
625        // will only contain lod 0. All tiles from other lod must be
626        // update through the trpgPageManager::AckLoad(tile info)
627        if(lod != 0)
628            doUpdate = false;
629    }
630    if(doUpdate)
631    {
632        // Sort the currently loaded stuff into a spatial array
633        //  so we can figure out what needs to be loaded in addition.
634        int dx,dy;
635        dx = ne.x - sw.x+1;  dy = ne.y - sw.y+1;
636        tmpCurrent.resize(dx*dy);
637        for (i=0;i<tmpCurrent.size();i++)  tmpCurrent[i] = false;
638        for (i=0;i<current.size();i++) {
639            trpgManagedTile *tile = current[i];
640            if (tile) {
641                int tileX,tileY,tileLod;
642                tile->GetTileLoc(tileX,tileY,tileLod);
643                tmpCurrent[(tileY-sw.y)*dx + (tileX-sw.x)] = true;
644            }
645        }
646
647        // Now figure out which ones are missing and add them
648        //  to the load list
649        for (int x=0;x<dx;x++) {
650            for (int y=0;y<dy;y++) {
651                if (!tmpCurrent[y*dx + x]) {
652                    // Allocate a new tile
653                    trpgManagedTile *tile = NULL;
654                    if (freeList.size() > 0) {
655                        tile = freeList[0];
656                        freeList.pop_front();
657                    } else
658                        tile = new trpgManagedTile();
659                    tile->SetTileLoc(x+sw.x,y+sw.y,lod);
660                    trpgwAppAddress addr;
661                    float32 zmin, zmax;
662
663                    if(tileTable && tileTable->GetTile(x+sw.x, y+sw.y, lod, addr, zmin, zmax))
664                        tile->SetTileAddress(addr);
665
666                    load.push_back(tile);
667                }
668            }
669        }
670    }
671
672    // That's it.  All the rest is handled by the caller
673    //  iterating through the tiles to load and unload.
674}
675
676// Get the list of currently loaded tiles that falls wiithin the area calculted from
677// the given paging distance
678void trpgPageManager::LodPageInfo::GetLoadedTileWithin(double pagingDistance, std::vector<trpgManagedTile*>& tileList)
679{
680    trpg2iPoint aoi_size((int)(pagingDistance/cellSize.x) +1,
681             (int)(pagingDistance/cellSize.y) +1);
682
683    // Calculate the area that we must check, in parent cell coordinate
684    trpg2iPoint sw, ne;
685    sw.x = cell.x - aoi_size.x;
686    sw.y = cell.y - aoi_size.y;
687    ne.x = cell.x + aoi_size.x;
688    ne.y = cell.y + aoi_size.y;
689    sw.x = MAX(0,sw.x);
690    sw.y = MAX(0,sw.y);
691    ne.x = MIN(lodSize.x-1,ne.x);
692    ne.y = MIN(lodSize.y-1,ne.y);
693
694    tileList.clear();
695
696    for (unsigned i=0; i <current.size(); i++) {
697        if (current[i] && isWithin(current[i],sw,ne))
698            tileList.push_back(current[i]);
699    }
700}
701void trpgPageManager::LodPageInfo::Print(trpgPrintBuffer &buf)
702{
703    char line[1024];
704    unsigned int i;
705
706    sprintf(line,"lod = %d,  valid = %s",lod,(valid ? "yes" : "no")); buf.prnLine(line);
707    sprintf(line,"pageDist = %f,  maxNumTiles = %d",pageDist,maxNumTiles);  buf.prnLine(line);
708    sprintf(line,"cellSize = (%f,%f)",cellSize.x,cellSize.y);  buf.prnLine(line);
709    sprintf(line,"cell = (%d,%d),  aoiSize = (%d,%d),  lodSize = (%d,%d)",cell.x,cell.y,aoiSize.x,aoiSize.y,lodSize.x,lodSize.y);  buf.prnLine(line);
710
711    sprintf(line,"Loads:  (activeLoad = %s)",(activeLoad ? "yes" : "no"));  buf.prnLine(line);
712    buf.IncreaseIndent();
713    for (i=0;i<load.size();i++)
714        if (load[i])
715            load[i]->Print(buf);
716    buf.DecreaseIndent();
717
718    sprintf(line,"Unloads:  (activeUnload = %s)",(activeUnload ? "yes" : "no"));  buf.prnLine(line);
719    buf.IncreaseIndent();
720    for (i=0;i<unload.size();i++)
721        if (unload[i])
722            unload[i]->Print(buf);
723    buf.DecreaseIndent();
724
725    buf.prnLine("Currently loaded:");
726    buf.IncreaseIndent();
727    for (i=0;i<current.size();i++)
728        if (current[i])
729            current[i]->Print(buf);
730    buf.DecreaseIndent();
731
732    sprintf(line,"Free list size = %d", (int)freeList.size());  buf.prnLine(line);
733}
734
735/* Page Manager methods
736   These are methods of the main trpgPageManager.  Check the header
737   file for more detailed information.
738*/
739
740trpgPageManager::trpgPageManager()
741{
742    scale = 1.0;
743    valid = false;
744    // This should be sufficiently unlikely
745    pagePt.x = -1e20;  pagePt.y = -1e20;
746}
747
748trpgPageManager::~trpgPageManager()
749{
750}
751
752void trpgPageManager::Init(trpgr_Archive *inArch)
753{
754    archive = inArch;
755
756    // We're resetting everything.  In general, Init should only
757    //  be called once, but it'll work fine if you call it more than once.
758    lastLoad = None;
759    lastTile = NULL;
760    lastLod = -1;
761
762    // Need to know the number of terrain LODs
763    const trpgHeader *head = archive->GetHeader();
764    int numLod;
765    head->GetNumLods(numLod);
766    head->GetVersion(majorVersion, minorVersion);
767
768    // Reset the terrain LOD paging classes.
769    valid = true;
770    pageInfo.resize(numLod);
771    for (int i=0;i<numLod;i++) {
772        if(i > 3)
773            pageInfo[i].Init(archive,i,scale, 4);
774        else
775            pageInfo[i].Init(archive,i,scale);
776    }
777}
778
779// We might want to init only to support the tile table content.
780// For Version 2.1 the tile table contain only lod 0.
781// We might want to do that to use another paging scheme for
782// lower lod
783void trpgPageManager::Init(trpgr_Archive *inArch, int maxLod)
784{
785    archive = inArch;
786
787    // We're resetting everything.  In general, Init should only
788    //  be called once, but it'll work fine if you call it more than once.
789    lastLoad = None;
790    lastTile = NULL;
791    lastLod = -1;
792
793    // Need to know the number of terrain LODs
794    const trpgHeader *head = archive->GetHeader();
795    int numLod;
796    head->GetNumLods(numLod);
797    head->GetVersion(majorVersion, minorVersion);
798
799    if(maxLod > numLod)
800        maxLod = numLod;
801
802    // Reset the terrain LOD paging classes.
803    valid = true;
804    pageInfo.resize(maxLod);
805    for (int i=0;i<maxLod;i++) {
806        if(i > 3)
807            pageInfo[i].Init(archive,i,scale, 4);
808        else
809            pageInfo[i].Init(archive,i,scale);
810    }
811}
812
813bool trpgPageManager::SetPageDistFactor(double inFact)
814{
815    // A scaling factor less than 1 will break the archive display.
816    if (inFact <= 1.0)
817        return false;
818
819    scale = inFact;
820
821    return true;
822}
823
824bool trpgPageManager::SetLocation(trpg2dPoint &pt)
825{
826    // Do a basic sanity check
827    if (!valid || (pagePt.x == pt.x && pagePt.y == pt.y))
828        return false;
829    pagePt = pt;
830
831    // Call each terrain LOD and let if figure out if something
832    //  has changed.
833    bool change = false;
834    for (unsigned int i=0;i<pageInfo.size();i++) {
835        if (pageInfo[i].SetLocation(pt))
836            change = true;
837    }
838
839    if(majorVersion == 2 && minorVersion >= 1 && change) {
840
841        // Version 2.1 and over
842        // Since we don't have a tile table for lod > 0,
843        // we must rely on the parent to see if children
844        // tiles have to be loaded:
845        // First we get the list of parent tiles that falls
846        // in the area of interest of the children,
847        // Second we add to the load list all the parent's
848        // children that are no already part of the list
849
850        for(unsigned int lodIdx = 1; lodIdx < pageInfo.size(); ++lodIdx) {
851
852            LodPageInfo& parentInfo = pageInfo[lodIdx -1];
853            LodPageInfo& childInfo = pageInfo[lodIdx];
854
855            // Get the list of parents tile that are currently
856            // loaded in the children aoi
857            std::vector<trpgManagedTile*> parentList;
858            parentInfo.GetLoadedTileWithin(childInfo.GetPageDistance(), parentList);
859
860            // Add the children of those parents to the load list
861            // of the children info, if they are not already there
862            childInfo.AddChildrenToLoadList(parentList);
863        }
864
865    }
866
867    return change;
868}
869
870trpgManagedTile *trpgPageManager::GetNextLoad()
871{
872    // If we're already doing something, let them know about it
873    if (lastLoad != None)
874        throw 1;
875
876    // Look for anything that needs loaded
877    // Start with lowest LOD, work up to highest
878    trpgManagedTile *tile = NULL;
879    for (unsigned int i=0;i<pageInfo.size();i++) {
880        LodPageInfo &info = pageInfo[i];
881        if ((tile = info.GetNextLoad()))
882            break;
883        }
884
885        // Found one.  Now the user has to load it.
886        if (tile) {
887        lastLoad = Load;
888        lastTile = tile;
889        lastLod = tile->location.lod;
890    }
891
892    return tile;
893}
894
895void trpgPageManager::AckLoad()
896{
897    std::vector<TileLocationInfo> children;
898    AckLoad(children);
899}
900void trpgPageManager::AckLoad(std::vector<TileLocationInfo> const& children)
901{
902    // If we're not in the middle of a load, register our displeasure
903    if (lastLoad != Load)
904        throw 1;
905
906    if(majorVersion >= 2 && minorVersion >=1)
907    {
908        if(children.size() > 0)
909        {
910            LodPageInfo& childInfo = pageInfo[lastLod+1];
911            for(unsigned int idx = 0; idx < children.size(); ++idx)
912            {
913                TileLocationInfo const&childLocInfo = children[idx];
914                if(childLocInfo.lod != lastLod+1)
915                    continue; // Something wrong here
916                childInfo.AddToLoadList(childLocInfo.x, childLocInfo.y, childLocInfo.addr);
917
918                // Also save info in parent tile
919                lastTile->SetChildLocationInfo(idx, childLocInfo);
920
921            }
922        }
923    }
924
925    pageInfo[lastLod].AckLoad();
926    lastLoad = None;
927    lastTile = NULL;
928}
929
930void trpgPageManager::AddGroupID(trpgManagedTile *tile,int groupID,void *data)
931{
932    groupMap[groupID] = data;
933    tile->AddGroupID(groupID);
934}
935
936void *trpgPageManager::GetGroupData(int groupID)
937{
938    ManageGroupMap::const_iterator p = groupMap.find(groupID);
939    if (p != groupMap.end())
940        return (*p).second;
941
942    return NULL;
943}
944
945trpgManagedTile *trpgPageManager::GetNextUnload()
946{
947    // If we're already doing something, let them know about it
948    if (lastLoad != None)
949        throw 1;
950
951    // Look for anything that needs unloaded
952    // Start with highest LOD, work down to lowest
953    trpgManagedTile *tile = NULL;
954    for (int i=pageInfo.size()-1;i>=0;i--) {
955        LodPageInfo &info = pageInfo[i];
956        if ((tile = info.GetNextUnload()))
957            break;
958    }
959
960    // Found one.  Now the user has to unload it.
961    if (tile) {
962        lastLoad = Unload;
963        lastTile = tile;
964        lastLod = tile->location.lod;
965    }
966
967    return tile;
968}
969
970void trpgPageManager::AckUnload()
971{
972    // If we're not in the middle of an unload, let 'em know.
973    if (lastLoad != Unload)
974        throw 1;
975
976    // Remove this tile's group IDs from the map
977    const std::vector<int> *groupIDs = lastTile->GetGroupIDs();
978    for (unsigned int i=0;i<groupIDs->size();i++) {
979        ManageGroupMap::iterator p = groupMap.find((*groupIDs)[i]);
980        if (p != groupMap.end())
981            groupMap.erase(p);
982    }
983
984    LodPageInfo &info = pageInfo[lastLod];
985    info.AckUnload();
986    lastLoad = None;
987    lastTile = NULL;
988}
989
990bool trpgPageManager::Stop()
991{
992    bool res=false;
993    for (unsigned int i=0;i<pageInfo.size();i++)
994        res |= pageInfo[i].Stop();
995
996    lastLoad = None;
997
998    return res;
999}
1000
1001void trpgPageManager::Print(trpgPrintBuffer &buf)
1002{
1003    char line[1024];
1004    sprintf(line,"Paging pos = (%f,%f),  scale = %f",pagePt.x,pagePt.y,scale);  buf.prnLine(line);
1005    buf.prnLine("Terrain LODs:");
1006
1007    for (unsigned int i=0;i<pageInfo.size();i++) {
1008        sprintf(line,"----Terrain lod %d---",i);  buf.prnLine(line);
1009            buf.IncreaseIndent();
1010        pageInfo[i].Print(buf);
1011        buf.DecreaseIndent();
1012    }
1013}
1014
1015void *trpgr_ChildRefCB::Parse(trpgToken tok, trpgReadBuffer& rbuf)
1016{
1017    // It should be a tile ref token, if not then something is wrong
1018    if(tok == TRPG_CHILDREF)
1019    {
1020        childList.push_back(trpgChildRef());
1021        trpgChildRef &childRef = childList.back();
1022        if(childRef.Read(rbuf))
1023            return &childRef;
1024        else
1025            return false;
1026
1027    }
1028    else
1029        return 0;
1030}
1031void trpgr_ChildRefCB::Reset()
1032{
1033    childList.clear();
1034}
1035
1036unsigned int trpgr_ChildRefCB::GetNbChildren() const
1037{
1038    return childList.size();
1039}
1040const trpgChildRef& trpgr_ChildRefCB::GetChildRef(unsigned int idx) const
1041{
1042    if(idx >= childList.size())
1043        throw std::invalid_argument(
1044                "trpgPageManageTester::ChildRefCB::GetChild(): index argument out of bound.");
1045    else
1046        return childList[idx];
1047}
1048
1049/* Page Manager Tester
1050   These methods are used to test the Paging Manager.
1051*/
1052
1053trpgPageManageTester::trpgPageManageTester()
1054{
1055    manager = NULL;
1056    archive = NULL;
1057}
1058
1059trpgPageManageTester::~trpgPageManageTester()
1060{
1061}
1062
1063void trpgPageManageTester::Init(trpgPrintBuffer *pBuf,trpgPageManager *pMan,trpgr_Archive *inArch)
1064{
1065    archive = inArch;
1066    manager = pMan;
1067    printBuf = pBuf;
1068
1069    if (!archive->isValid())
1070        throw 1;
1071
1072    const trpgHeader *header = archive->GetHeader();
1073    header->GetVersion(majorVersion, minorVersion);
1074
1075    tileParser.AddCallback(TRPG_CHILDREF, &childRefCB, false);
1076
1077    // Start up the paging manager
1078    manager->Init(archive);
1079}
1080
1081void trpgPageManageTester::RandomTest(int num,int seed)
1082{
1083    if (!manager || !archive || !printBuf)
1084        throw 1;
1085
1086    // Seed the random number generator so we can replicate runs
1087    if (seed != -1)
1088        srand(seed);
1089
1090    // Need the extents
1091    trpg2dPoint ll,ur,lod0Size;
1092    const trpgHeader *head = archive->GetHeader();
1093    head->GetExtents(ll,ur);
1094    head->GetTileSize(0,lod0Size);
1095
1096    // Give ourselves some space around the extents
1097    ll.x -= lod0Size.x/2.0;  ll.y -= lod0Size.y/2.0;
1098    ur.x += lod0Size.x/2.0;  ur.y += lod0Size.y/2.0;
1099
1100    // Jump around
1101    int i;
1102    char line[1024];
1103    for (i=0;i<num;i++) {
1104        // Generate a point
1105        double randNum1 = rand()/(double)RAND_MAX;
1106        double randNum2 = rand()/(double)RAND_MAX;
1107        trpg2dPoint pt;
1108        pt.x = (ur.x - ll.x)*randNum1;
1109        pt.y = (ur.y - ll.y)*randNum2;
1110
1111        // Jump to the point
1112        bool changes = manager->SetLocation(pt);
1113        sprintf(line,"Jumped to (%f,%f).  Tiles to load/unload = %s",pt.x,pt.y,
1114                (changes ? "yes" : "no"));  printBuf->prnLine(line);
1115
1116        // Process the results
1117        ProcessChanges();
1118    }
1119
1120    // Ask the page manager for its final status
1121    manager->Print(*printBuf);
1122
1123    manager->Stop();
1124}
1125
1126void trpgPageManageTester::Fly_LL_to_UR(double dist)
1127{
1128    char line[1024];
1129
1130    if (!manager || !archive || !printBuf)
1131        throw 1;
1132
1133    // Need the extents
1134    trpg2dPoint ll,ur,lod0Size;
1135    const trpgHeader *head = archive->GetHeader();
1136    head->GetExtents(ll,ur);
1137    head->GetTileSize(0,lod0Size);
1138
1139    // Give ourselves some space around the extents
1140    ll.x -= lod0Size.x/2.0;  ll.y -= lod0Size.y/2.0;
1141    ur.x += lod0Size.x/2.0;  ur.y += lod0Size.y/2.0;
1142
1143
1144    // Fly the path
1145    trpg2dPoint loc;   loc = ll;
1146    do {
1147        loc.x += dist;  loc.y += dist;
1148
1149        // Jump to next point
1150        bool changes = manager->SetLocation(loc);
1151        sprintf(line,"Moved to (%f,%f).  Tiles to load/unload = %s",loc.x,loc.y,
1152            (changes ? "yes" : "no"));  printBuf->prnLine(line);
1153
1154        // Process new location
1155        ProcessChanges();
1156    } while (loc.x < ur.x && loc.y < ur.y);
1157
1158    // Ask the page manager for its final status
1159    manager->Print(*printBuf);
1160
1161    manager->Stop();
1162}
1163
1164void trpgPageManageTester::ProcessChanges()
1165{
1166    char line[1024];
1167    int x,y,lod;
1168
1169    // Look for unloads to process
1170    trpgManagedTile *unloadTile;
1171    printBuf->prnLine("Tiles to unload:");
1172    printBuf->IncreaseIndent();
1173    while ((unloadTile = manager->GetNextUnload())) {
1174        unloadTile->GetTileLoc(x,y,lod);
1175        sprintf(line,"x = %d, y = %d, lod = %d",x,y,lod);  printBuf->prnLine(line);
1176        manager->AckUnload();
1177    }
1178    printBuf->DecreaseIndent();
1179
1180    // Look for loads to process
1181    trpgManagedTile *loadTile;
1182    printBuf->prnLine("Tiles to load:");
1183    printBuf->IncreaseIndent();
1184    while ((loadTile = manager->GetNextLoad())) {
1185        loadTile->GetTileLoc(x,y,lod);
1186        sprintf(line,"x = %d, y = %d, lod = %d",x,y,lod);  printBuf->prnLine(line);
1187
1188        if(majorVersion == 2 && minorVersion >= 1)
1189        {
1190            // Version 2.1 and over
1191            // We need to parse the loaded tile to get all of its children info
1192            const trpgwAppAddress& tileAddress = loadTile->GetTileAddress();
1193            trpgMemReadBuffer buf(archive->GetEndian());
1194            if(archive->ReadTile(tileAddress, buf))
1195            {
1196                childRefCB.Reset();
1197                if(tileParser.Parse(buf))
1198                {
1199                    //  childRefCB should now have alist of trpgChildRef found in the tile
1200                    unsigned int nbChildRef = childRefCB.GetNbChildren();
1201                    if(nbChildRef > 0)
1202                    {
1203                        std::vector<TileLocationInfo> locInfoList;
1204                        for(unsigned int idx = 0; idx < nbChildRef; ++idx)
1205                        {
1206                            const trpgChildRef& childRef = childRefCB.GetChildRef(idx);
1207                            locInfoList.push_back(TileLocationInfo());
1208                            TileLocationInfo& locInfo = locInfoList.back();
1209                            childRef.GetTileLoc(locInfo.x, locInfo.y, locInfo.lod);
1210                            childRef.GetTileAddress(locInfo.addr);
1211                        }
1212
1213                        manager->AckLoad(locInfoList);
1214                    }
1215                    else
1216                        manager->AckLoad();
1217                }
1218            }
1219            else
1220                manager->AckLoad();
1221        }
1222        else
1223            manager->AckLoad();
1224    }
1225    printBuf->DecreaseIndent();
1226}
Note: See TracBrowser for help on using the browser.