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

Revision 13041, 30.5 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#include <osg/Group>
2#include <osg/Object>
3#include <osg/Node>
4#include <osg/Notify>
5#include <osg/MatrixTransform>
6#include <osg/BoundingSphere>
7#include <osgDB/Registry>
8#include <osgDB/FileUtils>
9#include <osg/io_utils>
10
11#include <iostream>
12#include <sstream>
13#include <stdlib.h>
14#include <string.h>
15
16#include "ReaderWriterTXP.h"
17#include "TXPNode.h"
18#include "TXPArchive.h"
19#include "TXPPagedLOD.h"
20#include "TXPSeamLOD.h"
21#include "TileMapper.h"
22
23#define ReaderWriterTXPERROR(s) OSG_NOTICE << "txp::ReaderWriterTXP::" << (s) << " error: "
24
25
26
27namespace
28{
29    char gbuf[2048];
30}
31
32using namespace txp;
33
34int ReaderWriterTXP::_archiveId = 0;
35
36osgDB::ReaderWriter::ReadResult ReaderWriterTXP::local_readNode(const std::string& file, const osgDB::ReaderWriter::Options* options)
37{
38
39    std::string name = osgDB::getSimpleFileName(file);
40
41    // We load archive.txp
42    if (strncmp(name.c_str(),"archive",7)==0)
43    {
44        std::string fileName = osgDB::findDataFile( file, options );
45        if ( fileName.empty() )
46            return ReadResult::FILE_NOT_FOUND;
47
48        osg::ref_ptr<TXPNode> txpNode = new TXPNode;
49        txpNode->setArchiveName(fileName);
50        if (options)
51        {
52            txpNode->setOptions(options->getOptionString());
53        }
54
55
56        //modified by Brad Anderegg on May-27-08
57        //calling getArchive will create a new TXPArchive if the specified one does not exist
58        //we will set our osgdb loader options on the archive and set the appropriate archive on
59        //the txpNode.
60        int id = ++_archiveId;
61        osg::ref_ptr< TXPArchive > archive = createArchive(id,osgDB::getFilePath(fileName));
62
63        if (archive != NULL)
64        {
65            archive->setId(id);
66
67            if (options && options->getOptionString().find("loadMaterialsToStateSet")!=std::string::npos)
68            {
69               archive->SetMaterialAttributesToStateSetVar(true);
70            }
71
72            txpNode->loadArchive(archive.get());
73
74            return txpNode.get();
75        }
76        else
77        {
78            return ReadResult::ERROR_IN_READING_FILE;
79        }
80    }
81
82    // We load tileLOD_XxY_ID.txp
83    else if (strncmp(name.c_str(),"tile",4)==0)
84    {
85        int x,y,lod;
86        unsigned int id;
87        sscanf(name.c_str(),"tile%d_%dx%d_%u",&lod,&x,&y,&id);
88        osg::ref_ptr< TXPArchive > archive = getArchive(id,osgDB::getFilePath(file));
89        if (archive == NULL)
90            return ReadResult::ERROR_IN_READING_FILE;
91
92        // The way this is done a 'tile' should only be created for lod 0 only,
93        // something is wrong if this is no the case
94        if(lod != 0)
95        {
96            ReaderWriterTXPERROR("ReaderWriterTXP::local_readNode()") << "paged 'tile' should be at lod 0" << std::endl;
97            return ReadResult::ERROR_IN_READING_FILE;
98        }
99
100        trpgEndian endian = archive->GetEndian();
101        archive->ReadSubArchive( 0, 0, endian);
102        archive->ReadSubArchive( y, x, endian);
103
104//    std::cout << "Attempted " << x << " " << y << std::endl;
105
106        TXPArchive::TileInfo info;
107        if (!archive->getTileInfo(x,y,lod,info))
108            return ReadResult::ERROR_IN_READING_FILE;
109
110        std::vector<TXPArchive::TileLocationInfo> childrenLoc;
111        osg::ref_ptr<osg::Node> tileContent = getTileContent(info,x,y,lod,archive.get(), childrenLoc);
112
113        tileContent->setName("TileContent");
114
115        bool asChildren = false;
116        std::string childrenInfoStr;
117
118        int numLods = archive->getNumLODs();
119
120        int majorVersion, minorVersion;
121        archive->GetVersion(majorVersion, minorVersion);
122        if(majorVersion ==2 && minorVersion >=1)
123        {
124            // Version 2.1 and over
125            // The tile table only contains lod 0 and the children
126            // info are stored in its parent. SO if we do not want
127            // to be forced to reparse the parent we need to save that
128            // info. For now we just add it to the node name
129
130            if(childrenLoc.size() > 0)
131            {
132                asChildren = true;
133                createChildrenLocationString(childrenLoc, childrenInfoStr);
134            }
135        }
136        else
137        {
138            if (lod < (numLods-1)) asChildren = true;
139        }
140
141        if (asChildren)
142        {
143            char pagedLODfile[1024];
144            sprintf(pagedLODfile,"%s\\subtiles%d_%dx%d_%d",
145            archive->getDir(),
146            lod,
147            x,
148            y,
149            archive->getId());
150
151            strcat(pagedLODfile, childrenInfoStr.c_str());
152            strcat(pagedLODfile, ".txp");
153
154
155            // there are tile sets which do not maintain the z extents in
156            // the tile table.  This attempt to address the issue by using
157            // the geometry bounding sphere.  The downside is that this is
158            // not coupled to the generation and may result in runtime cracks
159            if (info.center.z() == 0)
160            {
161                osg::BoundingSphere bSphere = tileContent->getBound();
162
163                info.center.z() = bSphere.center().z();
164                info.radius = bSphere.radius();
165            }
166
167
168            osg::ref_ptr<TXPPagedLOD> pagedLOD = new TXPPagedLOD;
169            // note: use maximum(info.maxRange,1e7) as just maxRange would result in some corner tiles from being culled out.
170            pagedLOD->addChild(tileContent.get(),info.minRange,osg::maximum(info.maxRange,1e7));
171            pagedLOD->setFileName(1,pagedLODfile);
172            pagedLOD->setRange(1,0,info.minRange);
173            pagedLOD->setCenter(info.center);
174            pagedLOD->setRadius(info.radius);
175            pagedLOD->setPriorityOffset(0,numLods-lod);
176            pagedLOD->setPriorityScale(0,1.0f);
177            pagedLOD->setNumChildrenThatCannotBeExpired(1);
178            pagedLOD->setTileId(x,y,lod);
179
180            const trpgHeader* header = archive->GetHeader();
181            trpgHeader::trpgTileType tileType;
182            header->GetTileOriginType(tileType);
183            if(tileType == trpgHeader::TileLocal)
184            {
185                osg::Vec3d sw(info.bbox._min);
186                pagedLOD->setCenter(info.center - sw);
187            }
188
189            return pagedLOD.get();
190        }
191        else
192            return tileContent.get();
193    }
194
195
196    // For 2.0 and lower we load subtilesLOD_XxY_ID.txp
197    // For 2.1 and over  we load subtilesLOD_XxY_ID_NBCHILD_{X_Y_FID_FOFFSET_ZMIN_ZMAX_X_Y_ADDR ....}.txp
198    else if (strncmp(name.c_str(),"sub",3)==0)
199    {
200        int x,y,lod;
201        unsigned int id;
202        sscanf(name.c_str(),"subtiles%d_%dx%d_%u",&lod,&x,&y,&id);
203        osg::ref_ptr< TXPArchive > archive = getArchive(id,osgDB::getFilePath(file));
204        if (archive == NULL)
205            return ReadResult::ERROR_IN_READING_FILE;
206
207        int majorVersion, minorVersion;
208        archive->GetVersion(majorVersion, minorVersion);
209
210        std::vector<TXPArchive::TileLocationInfo> childrenLoc;
211
212        osg::ref_ptr<osg::Group> subtiles = new osg::Group;
213
214        int numLods = archive->getNumLODs();
215
216        if(majorVersion == 2  && minorVersion >= 1)
217        {
218            int nbChild;
219
220            sscanf(name.c_str(),"subtiles%d_%dx%d_%u_%d",&lod,&x,&y,&id, &nbChild);
221            std::vector<TXPArchive::TileLocationInfo> locs;
222            bool status = true;
223            status = extractChildrenLocations(name, lod, locs, nbChild);
224            if(majorVersion >= TRPG_NOMERGE_VERSION_MAJOR && minorVersion >=TRPG_NOMERGE_VERSION_MINOR && archive->GetHeader()->GetIsMaster())
225            {
226                for(int idx=0;idx<nbChild;idx++)
227                {
228                    //figure out the block row/col
229                    int blockx,blocky;
230                    unsigned int denom = (1 << locs[idx].lod); // this should work up to lod 31
231                    blockx = locs[idx].x/denom;
232                    blocky = locs[idx].y/denom;
233                    locs[idx].addr.col = blockx;
234                    locs[idx].addr.row = blocky;
235                }
236            }
237
238            if(!status)
239            {
240                ReaderWriterTXPERROR("ReaderWriterTXP::local_readNode()") << "'subtile' filename children parsing failed " << std::endl;
241                return ReadResult::ERROR_IN_READING_FILE;
242            }
243
244            const trpgHeader* header = archive->GetHeader();
245            trpgHeader::trpgTileType tileType;
246            header->GetTileOriginType(tileType);
247
248            TXPArchive::TileLocationInfo plInfo;
249            plInfo.x = x;
250            plInfo.y = y;
251            plInfo.lod = lod;
252            TXPArchive::TileInfo parentInfo;
253            archive->getTileInfo(plInfo,parentInfo);
254
255            for(int idx = 0; idx < nbChild; ++idx)
256            {
257                std::vector<TXPArchive::TileLocationInfo> childrenChildLoc;
258
259                TXPArchive::TileLocationInfo& loc = locs[idx];
260
261                TXPArchive::TileInfo info;
262                if (!archive->getTileInfo(loc,info))
263                    continue;
264
265                osg::ref_ptr<osg::Node> tileContent = getTileContent(info, loc, archive.get(), childrenChildLoc);
266
267                tileContent->setName("TileContent");
268
269                if(childrenChildLoc.size() > 0)
270                {
271                    std::string childInfoStr;
272                    createChildrenLocationString(childrenChildLoc, childInfoStr);
273
274                    char pagedLODfile[1024];
275                    sprintf(pagedLODfile,"%s\\subtiles%d_%dx%d_%d%s.txp",
276                        archive->getDir(),
277                        loc.lod,
278                        loc.x,
279                        loc.y,
280                        archive->getId(),
281                        childInfoStr.c_str());
282
283                    // there are tile sets which do not maintain the z extents in
284                    // the tile table.  This attempt to address the issue by using
285                    // the geometry bounding sphere.  The downside is that this is
286                    // not coupled to the generation and may result in runtime cracks
287                    if (info.center.z() == 0)
288                    {
289                        osg::BoundingSphere bSphere = tileContent->getBound();
290
291                        info.center.z() = bSphere.center().z();
292                        info.radius = bSphere.radius();
293                    }
294
295                    osg::ref_ptr<TXPPagedLOD> pagedLOD = new TXPPagedLOD;
296                            // note: use maximum(info.maxRange,1e7) as just maxRange would result in some corner tiles from being culled out.
297                    pagedLOD->addChild(tileContent.get(),info.minRange,osg::maximum(info.maxRange,1e7));
298                    pagedLOD->setFileName(1,pagedLODfile);
299                    pagedLOD->setRange(1,0,info.minRange);
300                    pagedLOD->setCenter(info.center);
301                    pagedLOD->setRadius(info.radius);
302                    pagedLOD->setPriorityOffset(0,numLods - loc.lod);
303                    pagedLOD->setPriorityScale(0,1.0f);
304                    pagedLOD->setNumChildrenThatCannotBeExpired(1);
305                    pagedLOD->setTileId(loc.x, loc.y, loc.lod);
306
307                    if(tileType == trpgHeader::TileLocal)
308                    {
309                        osg::Vec3d center(info.center - parentInfo.bbox._min);
310                        osg::Vec3d sw(info.bbox._min - parentInfo.bbox._min);
311                        sw[2] = 0.0;
312                        pagedLOD->setCenter(center - sw);
313                        osg::Matrix offset;
314                        offset.setTrans(sw);
315                        osg::MatrixTransform *tform = new osg::MatrixTransform(offset);
316                        tform->addChild(pagedLOD.get());
317                        subtiles->addChild(tform);
318                    }
319                    else
320                        subtiles->addChild(pagedLOD.get());
321                        subtiles->setUserData(new TileIdentifier(loc.x, loc.y, loc.lod)); // is this really needed?
322                }
323                else
324                {
325                    subtiles->setUserData(new TileIdentifier(loc.x, loc.y, loc.lod));
326                    if(tileType == trpgHeader::TileLocal)
327                    {
328                        osg::Vec3d center(info.center - parentInfo.bbox._min);
329                        osg::Vec3d sw(info.bbox._min - parentInfo.bbox._min);
330                        sw[2] = 0.0;
331                        osg::Matrix offset;
332                        offset.setTrans(sw);
333                        osg::MatrixTransform *tform = new osg::MatrixTransform(offset);
334                        tform->addChild(tileContent.get());
335                        subtiles->addChild(tform);
336                    }
337                    else
338                        subtiles->addChild(tileContent.get());
339                }
340            }
341        }
342        else
343        {
344
345            int sizeX, sizeY;
346            archive->getLODSize(lod+1,sizeX,sizeY);
347
348            const trpgHeader* header = archive->GetHeader();
349            trpgHeader::trpgTileType tileType;
350            header->GetTileOriginType(tileType);
351
352            TXPArchive::TileInfo parentInfo;
353            archive->getTileInfo(x,y,lod,parentInfo);
354
355            for (int ix = 0; ix < 2; ix++)
356            {
357                for (int iy = 0; iy < 2; iy++)
358                {
359                    int tileX = x*2+ix;
360                    int tileY = y*2+iy;
361                    int tileLOD = lod+1;
362
363                    TXPArchive::TileInfo info;
364                    if (!archive->getTileInfo(tileX,tileY,tileLOD,info))
365                    continue;
366
367                    osg::ref_ptr<osg::Node> tileContent = getTileContent(info,tileX,tileY,tileLOD,archive.get(), childrenLoc);
368
369                    tileContent->setName("TileContent");
370
371                    if (tileLOD < (numLods-1))
372                    {
373                        char pagedLODfile[1024];
374                        sprintf(pagedLODfile,"%s\\subtiles%d_%dx%d_%d.txp",
375                            archive->getDir(),
376                            tileLOD,
377                            tileX,
378                            tileY,
379                            archive->getId());
380
381                        // there are tile sets which do not maintain the z extents in
382                        // the tile table.  This attempt to address the issue by using
383                        // the geometry bounding sphere.  The downside is that this is
384                        // not coupled to the generation and may result in runtime cracks
385                        if (info.center.z() == 0)
386                        {
387                            osg::BoundingSphere bSphere = tileContent->getBound();
388
389                            info.center.z() = bSphere.center().z();
390                            info.radius = bSphere.radius();
391                        }
392
393                        osg::ref_ptr<TXPPagedLOD> pagedLOD = new TXPPagedLOD;
394                                    // note: use maximum(info.maxRange,1e7) as just maxRange would result in some corner tiles from being culled out.
395                        pagedLOD->addChild(tileContent.get(),info.minRange,osg::maximum(info.maxRange,1e7));
396                        pagedLOD->setFileName(1,pagedLODfile);
397                        pagedLOD->setRange(1,0,info.minRange);
398                        pagedLOD->setCenter(info.center);
399                        pagedLOD->setRadius(info.radius);
400                        pagedLOD->setPriorityOffset(0,numLods-lod);
401                        pagedLOD->setPriorityScale(0,1.0f);
402                        pagedLOD->setNumChildrenThatCannotBeExpired(1);
403                        pagedLOD->setTileId(tileX,tileY,tileLOD);
404
405                        if(tileType == trpgHeader::TileLocal)
406                        {
407                            osg::Vec3d center(info.center - parentInfo.bbox._min);
408                            osg::Vec3d sw(info.bbox._min - parentInfo.bbox._min);
409                            sw[2] = 0.0;
410                            pagedLOD->setCenter(center - sw);
411                            osg::Matrix offset;
412                            offset.setTrans(sw);
413                            osg::MatrixTransform *tform = new osg::MatrixTransform(offset);
414                            tform->addChild(pagedLOD.get());
415                            subtiles->addChild(tform);
416                        }
417                        else
418                            subtiles->addChild(pagedLOD.get());
419                    }
420                    else
421                    {
422                        subtiles->setUserData(new TileIdentifier(tileX,tileY,tileLOD));
423                        if(tileType == trpgHeader::TileLocal)
424                        {
425                            osg::Vec3d center(info.center - parentInfo.bbox._min);
426                            osg::Vec3d sw(info.bbox._min - parentInfo.bbox._min);
427                            sw[2] = 0.0;
428                            osg::Matrix offset;
429                            offset.setTrans(sw);
430                            osg::MatrixTransform *tform = new osg::MatrixTransform(offset);
431                            tform->addChild(tileContent.get());
432                            subtiles->addChild(tform);
433                        }
434                        else
435                            subtiles->addChild(tileContent.get());
436                    }
437
438                }
439            }
440        }
441
442        //OSG_NOTICE << "Subtiles for " << x << " " << y << " " << lod << " lodaded" << std::endl;
443        return subtiles.get();
444    }
445
446    return ReadResult::ERROR_IN_READING_FILE;
447}
448
449// If you change this then you have to change extractChildrenLocation()
450void ReaderWriterTXP::createChildrenLocationString(const std::vector<TXPArchive::TileLocationInfo>& locs, std::string& locString) const
451{
452    std::stringstream theLoc;
453
454    if(locs.size() == 0)
455    {
456        theLoc << "_" << locs.size();
457    }
458    else
459    {
460
461        theLoc << "_" << locs.size() << "_" << "{" ;
462
463        for(unsigned int idx = 0; idx < locs.size(); ++idx)
464        {
465            const TXPArchive::TileLocationInfo& loc = locs[idx];
466
467            theLoc << loc.x
468                   << "_"
469                   << loc.y
470                   << "_"
471                   << loc.addr.file
472                   << "_"
473                   << loc.addr.offset
474                   << "_"
475                   << loc.zmin
476                   << "_"
477                   << loc.zmax;
478            if(idx != locs.size() -1)
479                theLoc << "_";
480        }
481    }
482
483    theLoc << "}" << std::ends;
484
485    locString = theLoc.str();
486}
487bool ReaderWriterTXP::extractChildrenLocations(const std::string& name, int parentLod, std::vector<TXPArchive::TileLocationInfo>& locs, int nbChild) const
488{
489    locs.clear();
490
491    if(nbChild == 0)
492        return true;
493
494    locs.resize(nbChild);
495
496    // We look for '{', which should be the start of the list of {x,y,addr} children data
497    // '}' should end the list.
498    // We expect: X,Y,FID,FOFFSET,ZMIN,ZMAX
499    std::string::size_type startOfList = name.find_last_of('{');
500    if(startOfList == std::string::npos)
501        return false;
502
503    std::string::size_type endOfList = name.find_last_of('}');
504    if(endOfList == std::string::npos)
505        return false;
506
507    // Extract the data
508    strcpy(gbuf, name.substr(startOfList + 1, endOfList - startOfList - 1).c_str());
509    char *token = strtok( gbuf, "_" );
510
511    int nbTokenRead = 0;
512    for(int idx = 0; idx < nbChild; idx++)
513    {
514        // X
515        if(!token)
516            break;
517        locs[idx].x = atoi(token);
518        nbTokenRead++;
519
520        // Y
521        token = strtok(0, "_");
522        if(!token)
523            break;
524        locs[idx].y = atoi(token);
525        nbTokenRead++;
526
527        // FID
528        token = strtok(0, "_");
529        if(!token)
530            break;
531        locs[idx].addr.file = atoi(token);
532        nbTokenRead++;
533
534        // OFFSET
535        token = strtok(0, "_");
536        if(!token)
537            break;
538        locs[idx].addr.offset = atoi(token);
539        nbTokenRead++;
540
541        // ZMIN
542        token = strtok(0, "_");
543        if(!token)
544            break;
545        locs[idx].zmin = osg::asciiToFloat(token);
546        nbTokenRead++;
547
548        // ZMAX
549        token = strtok(0, "_");
550        if(!token)
551            break;
552        locs[idx].zmax = osg::asciiToFloat(token);
553        nbTokenRead++;
554
555        locs[idx].lod = parentLod+1;
556
557
558
559        token = strtok(0, "_");
560    }
561
562    if(nbTokenRead != nbChild*6)
563        return false;
564    else
565        return true;
566
567
568}
569
570std::string ReaderWriterTXP::getArchiveName(const std::string& dir)
571{
572#ifdef _WIN32
573    const char _PATHD = '\\';
574#elif defined(macintosh)
575    const char _PATHD = ':';
576#else
577    const char _PATHD = '/';
578#endif
579
580    return dir+_PATHD+"archive.txp";
581}
582
583osg::ref_ptr< TXPArchive > ReaderWriterTXP::getArchive(int id, const std::string& dir)
584{
585    osg::ref_ptr< TXPArchive > archive = NULL;
586
587    std::map< int,osg::ref_ptr<TXPArchive> >::iterator iter = _archives.find(id);
588
589    if (iter != _archives.end())
590    {
591        archive = iter->second.get();
592    }
593    else
594    {
595        std::string archiveName = getArchiveName(dir);
596        ReaderWriterTXPERROR("getArchive()") << "archive id " << id << " not found: \"" << archiveName << "\"" << std::endl;
597    }
598    return archive;
599}
600
601osg::ref_ptr< TXPArchive > ReaderWriterTXP::createArchive(int id, const std::string& dir)
602{
603    std::string archiveName = getArchiveName(dir);
604
605    osg::ref_ptr< TXPArchive > archive = getArchive(id, dir);
606    if (archive != NULL)
607    {
608        ReaderWriterTXPERROR("createArchive()") << "archive id " << id << " already exists: \"" << archiveName << "\"" << std::endl;
609        return NULL;
610    }
611
612    archive = new TXPArchive;
613    if (archive->openFile(archiveName) == false)
614    {
615        ReaderWriterTXPERROR("createArchive()") << "failed to load archive: \"" << archiveName << "\"" << std::endl;
616        return NULL;
617    }
618
619    if (archive->loadMaterials() == false)
620    {
621        ReaderWriterTXPERROR("createArchive()") << "failed to load materials from archive: \"" << archiveName << "\"" << std::endl;
622        return NULL;
623    }
624
625    if (archive->loadModels() == false)
626    {
627        ReaderWriterTXPERROR("createArchive()") << "failed to load models from archive: \"" << archiveName << "\"" << std::endl;
628        return NULL;
629    }
630
631    if (archive->loadLightAttributes() == false)
632    {
633        ReaderWriterTXPERROR("createArchive()") << "failed to load light attributes from archive: \"" << archiveName << "\"" << std::endl;
634        return NULL;
635    }
636
637    if (archive->loadTextStyles() == false)
638    {
639        ReaderWriterTXPERROR("createArchive()") << "failed to load text styles from archive: \"" << archiveName << "\"" << std::endl;
640        return NULL;
641    }
642
643    archive->setId(id);
644
645    _archives[id] = archive;
646
647    return archive;
648}
649
650bool ReaderWriterTXP::removeArchive( int id )
651{
652    OSG_INFO<<"ReaderWriterTXP::removeArchive(id="<<id<<")"<<std::endl;
653    //return (_archives.erase(id) >= 1);
654    bool result=_archives.erase(id) >= 1;
655    OSG_WARN<<"remove archive " << id << " size " << _archives.size()
656        << " result " << result << std::endl;
657    return result;
658
659}
660
661class SeamFinder: public osg::NodeVisitor
662{
663public:
664    SeamFinder(int x, int y, int lod, const TXPArchive::TileInfo& info, TXPArchive *archive ):
665    osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
666    _x(x), _y(y), _lod(lod), _info(info), _archive(archive)
667    {}
668
669    virtual void apply(osg::Group& group)
670    {
671        for (unsigned int i = 0; i < group.getNumChildren(); i++)
672        {
673            osg::Node* child = group.getChild(i);
674            osg::Node* seam = seamReplacement(child);
675            if (child != seam)
676            {
677                group.replaceChild(child,seam);
678            }
679            else
680            {
681                child->accept(*this);
682            }
683        }
684    }
685
686protected:
687    osg::Node* seamReplacement(osg::Node* node);
688
689    SeamFinder& operator = (const SeamFinder&) { return *this; }
690
691    int _x, _y, _lod;
692    const TXPArchive::TileInfo& _info;
693    TXPArchive *_archive;
694};
695
696#define equalDoubles(a, b) (fabs(a-b) < 0.001)
697
698osg::Node* SeamFinder::seamReplacement(osg::Node* node)
699{
700    osg::Group* group = node->asGroup();
701    if ( group == 0 )
702        return node;
703
704    std::vector<osg::Node*> nonSeamChildren;
705    osg::LOD* hiRes = 0;
706    osg::LOD* loRes = 0;
707
708    const trpgHeader* header = _archive->GetHeader();
709    trpgHeader::trpgTileType tileType;
710    header->GetTileOriginType(tileType);
711
712    for (unsigned int i = 0; i < group->getNumChildren(); i++)
713    {
714        osg::LOD* lod = dynamic_cast<osg::LOD*>(group->getChild(i));
715        if (lod == 0)
716        {
717            nonSeamChildren.push_back(group->getChild(i));
718            continue;
719        }
720
721        bool nonSeamChild = true;
722
723        // looks like the problem is in here - likely due to seamLOD info
724        // not being adjusted properly in tiled databases
725            // seam center is outside the bounding box of the tile
726        osg::Vec3 lodCenter = lod->getCenter();
727
728        if(tileType == trpgHeader::TileLocal)
729        {
730            trpg2dPoint tileExtents;
731            header->GetTileSize(0, tileExtents);
732            osg::BoundingBox bbox;
733            _archive->getExtents(bbox);
734            osg::Vec3 offset(0.0, 0.0, 0.0);
735
736            int divider = (0x1 << _lod);
737            // calculate which tile model is located in
738            tileExtents.x /= divider;
739            tileExtents.y /= divider;
740            offset[0] = _x*tileExtents.x;// + tileExtents.x*0.5;
741            offset[1] = _y*tileExtents.y;// + tileExtents.y*0.5;
742            lodCenter += offset;
743        }
744
745        if (!_info.bbox.contains(lodCenter))
746        {
747            const osg::LOD::RangeList& rangeList = lod->getRangeList();
748            if (!rangeList.size())
749            {
750                // TODO: Warn here
751                continue;
752            }
753
754            TXPArchive::TileInfo lod_plus_one_info;
755            if (!this->_archive->getTileInfo(_x,_y,_lod+1,lod_plus_one_info))
756            {
757                // TODO: Warn here
758                continue;
759            }
760
761            double lod_plus_oneSwitchInDistance =  lod_plus_one_info.maxRange;
762            double lod0SwitchInDistance =  _info.lod0Range;
763
764            // low res seam has min/max ranges of lod+1 range/lod 0 range
765            if (equalDoubles(lod_plus_oneSwitchInDistance,rangeList.at(0).first) && equalDoubles(lod0SwitchInDistance,rangeList.at(0).second))
766            {
767                if (loRes==0)
768                {
769                    loRes = lod;
770                    nonSeamChild = false;
771                }
772            }
773            else
774            // hi res seam has min/max ranges of 0 range/lod+1 range
775            if (rangeList.at(0).first==0.0 && equalDoubles(lod_plus_oneSwitchInDistance,rangeList.at(0).second))
776            {
777                if (hiRes==0)
778                {
779                    hiRes = lod;
780                    nonSeamChild = false;
781                }
782            }
783        }
784        if (nonSeamChild)
785        {
786            nonSeamChildren.push_back(lod);
787        }
788    }
789
790    if (loRes)
791    {
792        int dx = 0;
793        int dy = 0;
794        int lod = _lod;
795        osg::Vec3 lodCenter = loRes->getCenter();
796
797        if(tileType == trpgHeader::TileLocal)
798        {
799            trpg2dPoint tileExtents;
800            header->GetTileSize(0, tileExtents);
801            osg::BoundingBox bbox;
802            _archive->getExtents(bbox);
803            osg::Vec3 offset(0.0, 0.0, 0.0);
804
805            int divider = (0x1 << _lod);
806            // calculate which tile model is located in
807            tileExtents.x /= divider;
808            tileExtents.y /= divider;
809            offset[0] = _x*tileExtents.x;// + tileExtents.x*0.5;
810            offset[1] = _y*tileExtents.y;// + tileExtents.y*0.5;
811            lodCenter += offset;
812        }
813
814        osg::Vec3 delta = lodCenter-_info.center;
815        if (fabs(delta.x())>fabs(delta.y()))
816        {
817            if ( delta.x() < 0.0 )
818                --dx;    // west
819            else
820                dx++;                  // east
821        }
822        else
823        {
824            if ( delta.y() < 0.0 )
825                --dy;    // south
826            else
827                ++dy;                  // north
828        }
829
830        TXPSeamLOD* seam = new TXPSeamLOD(_x, _y, lod, dx, dy);
831        seam->setCenter(loRes->getCenter());
832        seam->addChild(loRes->getChild(0));        // low res
833        if (hiRes)
834        {
835            seam->addChild(hiRes->getChild(0));    // high res
836        }
837
838        if (nonSeamChildren.empty())
839        {
840            return seam;
841        }
842        else
843        {
844            osg::Group* newGroup = new osg::Group;
845
846            newGroup->addChild(seam);
847
848            for (unsigned int i = 0; i < nonSeamChildren.size(); i++)
849                newGroup->addChild(nonSeamChildren[i]);
850
851            return newGroup;
852        }
853    }
854
855    return node;
856}
857
858osg::Node* ReaderWriterTXP::getTileContent(const TXPArchive::TileInfo &info, int x, int y, int lod, TXPArchive* archive,  std::vector<TXPArchive::TileLocationInfo>& childrenLoc)
859{
860    if ( archive == 0 )
861        return false;
862
863    int majorVersion, minorVersion;
864    archive->GetVersion(majorVersion, minorVersion);
865
866    double realMinRange = info.minRange;
867    double realMaxRange = info.maxRange;
868    double  usedMaxRange = osg::maximum(info.maxRange,1e7);
869    osg::Vec3 tileCenter;
870    osg::Group* tileGroup = archive->getTileContent(x,y,lod,realMinRange,realMaxRange,usedMaxRange,tileCenter, childrenLoc);
871
872    // if group has only one child, then simply use its child.
873    while (tileGroup->getNumChildren()==1 && tileGroup->getChild(0)->asGroup())
874    {
875        tileGroup = tileGroup->getChild(0)->asGroup();
876    }
877
878    bool doSeam = false;
879    if(majorVersion == 2 && minorVersion >= 1)
880        doSeam = (childrenLoc.size() > 0);
881    else
882        doSeam = (lod < (archive->getNumLODs() - 1));
883
884    // Handle seams
885    if (doSeam)
886    {
887        SeamFinder sfv(x,y,lod,info,archive);
888        tileGroup->accept(sfv);
889    }
890
891    return tileGroup;
892}
893
894// this version only gets called if the TXP version is >= than 2.1
895osg::Node* ReaderWriterTXP::getTileContent(const TXPArchive::TileInfo &info, const TXPArchive::TileLocationInfo& loc, TXPArchive* archive,  std::vector<TXPArchive::TileLocationInfo>& childrenLoc)
896{
897    if ( archive == 0 )
898        return false;
899
900    // int numLods = archive->getNumLODs();
901
902    double realMinRange = info.minRange;
903    double realMaxRange = info.maxRange;
904    double usedMaxRange = osg::maximum(info.maxRange,1e7);
905    osg::Vec3 tileCenter;
906    osg::Group* tileGroup = archive->getTileContent(loc,realMinRange,realMaxRange,usedMaxRange,tileCenter, childrenLoc);
907
908    // if group has only one child, then simply use its child.
909    while (tileGroup->getNumChildren()==1 && tileGroup->getChild(0)->asGroup())
910    {
911        tileGroup = tileGroup->getChild(0)->asGroup();
912    }
913
914    // Handle seams
915    if (childrenLoc.size() > 0)
916    {
917        SeamFinder sfv(loc.x, loc.y, loc.lod, info, archive);
918        tileGroup->accept(sfv);
919    }
920
921    return tileGroup;
922}
923
924REGISTER_OSGPLUGIN(txp, ReaderWriterTXP)
Note: See TracBrowser for help on using the browser.