Files
OpenSceneGraph/src/osgPlugins/txp/ReaderWriterTXP.cpp
Robert Osfield 66246703bf Warning fixes
2018-09-11 15:32:44 +01:00

941 lines
31 KiB
C++

#include <osg/Group>
#include <osg/Object>
#include <osg/Node>
#include <osg/Notify>
#include <osg/MatrixTransform>
#include <osg/BoundingSphere>
#include <osgDB/Registry>
#include <osgDB/FileUtils>
#include <osg/io_utils>
#include <iostream>
#include <sstream>
#include <stdlib.h>
#include <string.h>
#include "ReaderWriterTXP.h"
#include "TXPNode.h"
#include "TXPArchive.h"
#include "TXPPagedLOD.h"
#include "TXPSeamLOD.h"
#include "TileMapper.h"
#define ReaderWriterTXPERROR(s) OSG_NOTICE << "txp::ReaderWriterTXP::" << (s) << " error: "
using namespace txp;
int ReaderWriterTXP::_archiveId = 0;
osgDB::ReaderWriter::ReadResult ReaderWriterTXP::local_readNode(const std::string& file, const osgDB::ReaderWriter::Options* options)
{
std::string name = osgDB::getSimpleFileName(file);
// We load archive.txp
if (strncmp(name.c_str(),"archive",7)==0)
{
std::string fileName = osgDB::findDataFile( file, options );
if ( fileName.empty() )
return ReadResult::FILE_NOT_FOUND;
osg::ref_ptr<TXPNode> txpNode = new TXPNode;
txpNode->setArchiveName(fileName);
if (options)
{
txpNode->setOptions(options->getOptionString());
}
//modified by Brad Anderegg on May-27-08
//calling getArchive will create a new TXPArchive if the specified one does not exist
//we will set our osgdb loader options on the archive and set the appropriate archive on
//the txpNode.
int id = ++_archiveId;
osg::ref_ptr< TXPArchive > archive = createArchive(id,osgDB::getFilePath(fileName));
if (archive != NULL)
{
archive->setId(id);
if (options && options->getOptionString().find("loadMaterialsToStateSet")!=std::string::npos)
{
archive->SetMaterialAttributesToStateSetVar(true);
}
txpNode->loadArchive(archive.get());
return txpNode.get();
}
else
{
return ReadResult::ERROR_IN_READING_FILE;
}
}
// We load tileLOD_XxY_ID.txp
else if (strncmp(name.c_str(),"tile",4)==0)
{
int x,y,lod;
unsigned int id;
if (sscanf(name.c_str(),"tile%d_%dx%d_%u",&lod,&x,&y,&id)!=4)
{
return ReadResult::ERROR_IN_READING_FILE;
}
osg::ref_ptr< TXPArchive > archive = getArchive(id,osgDB::getFilePath(file));
if (archive == NULL)
return ReadResult::ERROR_IN_READING_FILE;
// The way this is done a 'tile' should only be created for lod 0 only,
// something is wrong if this is no the case
if(lod != 0)
{
ReaderWriterTXPERROR("ReaderWriterTXP::local_readNode()") << "paged 'tile' should be at lod 0" << std::endl;
return ReadResult::ERROR_IN_READING_FILE;
}
trpgEndian endian = archive->GetEndian();
archive->ReadSubArchive( 0, 0, endian);
archive->ReadSubArchive( y, x, endian);
// std::cout << "Attempted " << x << " " << y << std::endl;
TXPArchive::TileInfo info;
if (!archive->getTileInfo(x,y,lod,info))
return ReadResult::ERROR_IN_READING_FILE;
std::vector<TXPArchive::TileLocationInfo> childrenLoc;
osg::ref_ptr<osg::Node> tileContent = getTileContent(info,x,y,lod,archive.get(), childrenLoc);
tileContent->setName("TileContent");
bool asChildren = false;
std::string childrenInfoStr;
int numLods = archive->getNumLODs();
int majorVersion, minorVersion;
archive->GetVersion(majorVersion, minorVersion);
if(majorVersion ==2 && minorVersion >=1)
{
// Version 2.1 and over
// The tile table only contains lod 0 and the children
// info are stored in its parent. SO if we do not want
// to be forced to reparse the parent we need to save that
// info. For now we just add it to the node name
if(childrenLoc.size() > 0)
{
asChildren = true;
createChildrenLocationString(childrenLoc, childrenInfoStr);
}
}
else
{
if (lod < (numLods-1)) asChildren = true;
}
if (asChildren)
{
std::stringstream pagedLODfile;
pagedLODfile<<archive->getDir()<<"\\subtiles"<<lod<<"_"<<x<<"x"<<y<<"_"<<archive->getId()<<childrenInfoStr<<".txp";
// there are tile sets which do not maintain the z extents in
// the tile table. This attempt to address the issue by using
// the geometry bounding sphere. The downside is that this is
// not coupled to the generation and may result in runtime cracks
if (info.center.z() == 0)
{
osg::BoundingSphere bSphere = tileContent->getBound();
info.center.z() = bSphere.center().z();
info.radius = bSphere.radius();
}
osg::ref_ptr<TXPPagedLOD> pagedLOD = new TXPPagedLOD;
// note: use maximum(info.maxRange,1e7) as just maxRange would result in some corner tiles from being culled out.
pagedLOD->addChild(tileContent.get(),info.minRange,osg::maximum(info.maxRange,1e7));
pagedLOD->setFileName(1,pagedLODfile.str());
pagedLOD->setRange(1,0,info.minRange);
pagedLOD->setCenter(info.center);
pagedLOD->setRadius(info.radius);
pagedLOD->setPriorityOffset(0,numLods-lod);
pagedLOD->setPriorityScale(0,1.0f);
pagedLOD->setNumChildrenThatCannotBeExpired(1);
pagedLOD->setTileId(x,y,lod);
const trpgHeader* header = archive->GetHeader();
trpgHeader::trpgTileType tileType;
header->GetTileOriginType(tileType);
if(tileType == trpgHeader::TileLocal)
{
osg::Vec3d sw(info.bbox._min);
pagedLOD->setCenter(info.center - sw);
}
return pagedLOD.get();
}
else
return tileContent.get();
}
// For 2.0 and lower we load subtilesLOD_XxY_ID.txp
// For 2.1 and over we load subtilesLOD_XxY_ID_NBCHILD_{X_Y_FID_FOFFSET_ZMIN_ZMAX_X_Y_ADDR ....}.txp
else if (strncmp(name.c_str(),"sub",3)==0)
{
int x,y,lod;
unsigned int id;
if (sscanf(name.c_str(),"subtiles%d_%dx%d_%u",&lod,&x,&y,&id)!=4)
{
return ReadResult::ERROR_IN_READING_FILE;
}
osg::ref_ptr< TXPArchive > archive = getArchive(id,osgDB::getFilePath(file));
if (archive == NULL)
{
return ReadResult::ERROR_IN_READING_FILE;
}
int majorVersion, minorVersion;
archive->GetVersion(majorVersion, minorVersion);
std::vector<TXPArchive::TileLocationInfo> childrenLoc;
osg::ref_ptr<osg::Group> subtiles = new osg::Group;
int numLods = archive->getNumLODs();
if(majorVersion == 2 && minorVersion >= 1)
{
int nbChild;
int numItemsRead = sscanf(name.c_str(),"subtiles%d_%dx%d_%u_%d",&lod,&x,&y,&id, &nbChild);
if (numItemsRead!=5)
{
ReaderWriterTXPERROR("ReaderWriterTXP::local_readNode()") << "'subtile' filename children parsing failed " << std::endl;
return ReadResult::ERROR_IN_READING_FILE;
}
std::vector<TXPArchive::TileLocationInfo> locs;
bool status = true;
status = extractChildrenLocations(name, lod, locs, nbChild);
if(majorVersion >= TRPG_NOMERGE_VERSION_MAJOR && minorVersion >=TRPG_NOMERGE_VERSION_MINOR && archive->GetHeader()->GetIsMaster())
{
for(int idx=0;idx<nbChild;idx++)
{
//figure out the block row/col
int blockx,blocky;
unsigned int denom = (1 << locs[idx].lod); // this should work up to lod 31
blockx = locs[idx].x/denom;
blocky = locs[idx].y/denom;
locs[idx].addr.col = blockx;
locs[idx].addr.row = blocky;
}
}
if(!status)
{
ReaderWriterTXPERROR("ReaderWriterTXP::local_readNode()") << "'subtile' filename children parsing failed " << std::endl;
return ReadResult::ERROR_IN_READING_FILE;
}
const trpgHeader* header = archive->GetHeader();
trpgHeader::trpgTileType tileType;
header->GetTileOriginType(tileType);
TXPArchive::TileLocationInfo plInfo;
plInfo.x = x;
plInfo.y = y;
plInfo.lod = lod;
TXPArchive::TileInfo parentInfo;
archive->getTileInfo(plInfo,parentInfo);
for(int idx = 0; idx < nbChild; ++idx)
{
std::vector<TXPArchive::TileLocationInfo> childrenChildLoc;
TXPArchive::TileLocationInfo& loc = locs[idx];
TXPArchive::TileInfo info;
if (!archive->getTileInfo(loc,info))
continue;
osg::ref_ptr<osg::Node> tileContent = getTileContent(info, loc, archive.get(), childrenChildLoc);
tileContent->setName("TileContent");
subtiles->setUserData(new TileIdentifier(loc.x, loc.y, loc.lod)); // is this really needed?
if(childrenChildLoc.size() > 0)
{
std::string childInfoStr;
createChildrenLocationString(childrenChildLoc, childInfoStr);
char pagedLODfile[1084];
sprintf(pagedLODfile,"%s\\subtiles%d_%dx%d_%d%s.txp",
archive->getDir(),
loc.lod,
loc.x,
loc.y,
archive->getId(),
childInfoStr.c_str());
// there are tile sets which do not maintain the z extents in
// the tile table. This attempt to address the issue by using
// the geometry bounding sphere. The downside is that this is
// not coupled to the generation and may result in runtime cracks
if (info.center.z() == 0)
{
osg::BoundingSphere bSphere = tileContent->getBound();
info.center.z() = bSphere.center().z();
info.radius = bSphere.radius();
}
osg::ref_ptr<TXPPagedLOD> pagedLOD = new TXPPagedLOD;
// note: use maximum(info.maxRange,1e7) as just maxRange would result in some corner tiles from being culled out.
pagedLOD->addChild(tileContent.get(),info.minRange,osg::maximum(info.maxRange,1e7));
pagedLOD->setFileName(1,pagedLODfile);
pagedLOD->setRange(1,0,info.minRange);
pagedLOD->setCenter(info.center);
pagedLOD->setRadius(info.radius);
pagedLOD->setPriorityOffset(0,numLods - loc.lod);
pagedLOD->setPriorityScale(0,1.0f);
pagedLOD->setNumChildrenThatCannotBeExpired(1);
pagedLOD->setTileId(loc.x, loc.y, loc.lod);
if(tileType == trpgHeader::TileLocal)
{
osg::Vec3d center(info.center - parentInfo.bbox._min);
osg::Vec3d sw(info.bbox._min - parentInfo.bbox._min);
sw[2] = 0.0;
pagedLOD->setCenter(center - sw);
osg::Matrix offset;
offset.setTrans(sw);
osg::MatrixTransform *tform = new osg::MatrixTransform(offset);
tform->addChild(pagedLOD.get());
subtiles->addChild(tform);
}
else
{
subtiles->addChild(pagedLOD.get());
}
}
else
{
subtiles->setUserData(new TileIdentifier(loc.x, loc.y, loc.lod));
if(tileType == trpgHeader::TileLocal)
{
osg::Vec3d center(info.center - parentInfo.bbox._min);
osg::Vec3d sw(info.bbox._min - parentInfo.bbox._min);
sw[2] = 0.0;
osg::Matrix offset;
offset.setTrans(sw);
osg::MatrixTransform *tform = new osg::MatrixTransform(offset);
tform->addChild(tileContent.get());
subtiles->addChild(tform);
}
else
{
subtiles->addChild(tileContent.get());
}
}
}
}
else
{
int sizeX, sizeY;
archive->getLODSize(lod+1,sizeX,sizeY);
const trpgHeader* header = archive->GetHeader();
trpgHeader::trpgTileType tileType;
header->GetTileOriginType(tileType);
TXPArchive::TileInfo parentInfo;
archive->getTileInfo(x,y,lod,parentInfo);
for (int ix = 0; ix < 2; ix++)
{
for (int iy = 0; iy < 2; iy++)
{
int tileX = x*2+ix;
int tileY = y*2+iy;
int tileLOD = lod+1;
TXPArchive::TileInfo info;
if (!archive->getTileInfo(tileX,tileY,tileLOD,info))
continue;
osg::ref_ptr<osg::Node> tileContent = getTileContent(info,tileX,tileY,tileLOD,archive.get(), childrenLoc);
tileContent->setName("TileContent");
if (tileLOD < (numLods-1))
{
char pagedLODfile[1094];
sprintf(pagedLODfile,"%s\\subtiles%d_%dx%d_%d.txp",
archive->getDir(),
tileLOD,
tileX,
tileY,
archive->getId());
// there are tile sets which do not maintain the z extents in
// the tile table. This attempt to address the issue by using
// the geometry bounding sphere. The downside is that this is
// not coupled to the generation and may result in runtime cracks
if (info.center.z() == 0)
{
osg::BoundingSphere bSphere = tileContent->getBound();
info.center.z() = bSphere.center().z();
info.radius = bSphere.radius();
}
osg::ref_ptr<TXPPagedLOD> pagedLOD = new TXPPagedLOD;
// note: use maximum(info.maxRange,1e7) as just maxRange would result in some corner tiles from being culled out.
pagedLOD->addChild(tileContent.get(),info.minRange,osg::maximum(info.maxRange,1e7));
pagedLOD->setFileName(1,pagedLODfile);
pagedLOD->setRange(1,0,info.minRange);
pagedLOD->setCenter(info.center);
pagedLOD->setRadius(info.radius);
pagedLOD->setPriorityOffset(0,numLods-lod);
pagedLOD->setPriorityScale(0,1.0f);
pagedLOD->setNumChildrenThatCannotBeExpired(1);
pagedLOD->setTileId(tileX,tileY,tileLOD);
if(tileType == trpgHeader::TileLocal)
{
osg::Vec3d center(info.center - parentInfo.bbox._min);
osg::Vec3d sw(info.bbox._min - parentInfo.bbox._min);
sw[2] = 0.0;
pagedLOD->setCenter(center - sw);
osg::Matrix offset;
offset.setTrans(sw);
osg::MatrixTransform *tform = new osg::MatrixTransform(offset);
tform->addChild(pagedLOD.get());
subtiles->addChild(tform);
}
else
subtiles->addChild(pagedLOD.get());
}
else
{
subtiles->setUserData(new TileIdentifier(tileX,tileY,tileLOD));
if(tileType == trpgHeader::TileLocal)
{
osg::Vec3d center(info.center - parentInfo.bbox._min);
osg::Vec3d sw(info.bbox._min - parentInfo.bbox._min);
sw[2] = 0.0;
osg::Matrix offset;
offset.setTrans(sw);
osg::MatrixTransform *tform = new osg::MatrixTransform(offset);
tform->addChild(tileContent.get());
subtiles->addChild(tform);
}
else
subtiles->addChild(tileContent.get());
}
}
}
}
//OSG_NOTICE << "Subtiles for " << x << " " << y << " " << lod << " lodaded" << std::endl;
return subtiles.get();
}
return ReadResult::ERROR_IN_READING_FILE;
}
// If you change this then you have to change extractChildrenLocation()
void ReaderWriterTXP::createChildrenLocationString(const std::vector<TXPArchive::TileLocationInfo>& locs, std::string& locString) const
{
std::stringstream theLoc;
if(locs.size() == 0)
{
theLoc << "_" << locs.size();
}
else
{
theLoc << "_" << locs.size() << "_" << "{" ;
for(unsigned int idx = 0; idx < locs.size(); ++idx)
{
const TXPArchive::TileLocationInfo& loc = locs[idx];
theLoc << loc.x
<< "_"
<< loc.y
<< "_"
<< loc.addr.file
<< "_"
<< loc.addr.offset
<< "_"
<< loc.zmin
<< "_"
<< loc.zmax;
if(idx != locs.size() -1)
theLoc << "_";
}
}
theLoc << "}" << std::ends;
locString = theLoc.str();
}
bool ReaderWriterTXP::extractChildrenLocations(const std::string& name, int parentLod, std::vector<TXPArchive::TileLocationInfo>& locs, int nbChild) const
{
locs.clear();
if(nbChild == 0)
return true;
locs.resize(nbChild);
// We look for '{', which should be the start of the list of {x,y,addr} children data
// '}' should end the list.
// We expect: X,Y,FID,FOFFSET,ZMIN,ZMAX
std::string::size_type startOfList = name.find_last_of('{');
if(startOfList == std::string::npos)
return false;
std::string::size_type endOfList = name.find_last_of('}');
if(endOfList == std::string::npos)
return false;
// Extract the data
std::string gbuf(name.substr(startOfList + 1, endOfList - startOfList - 1));
char *token = gbuf.empty() ? 0: strtok( &gbuf[0], "_" );
int nbTokenRead = 0;
for(int idx = 0; idx < nbChild; idx++)
{
// X
if(!token)
break;
locs[idx].x = atoi(token);
nbTokenRead++;
// Y
token = strtok(0, "_");
if(!token)
break;
locs[idx].y = atoi(token);
nbTokenRead++;
// FID
token = strtok(0, "_");
if(!token)
break;
locs[idx].addr.file = atoi(token);
nbTokenRead++;
// OFFSET
token = strtok(0, "_");
if(!token)
break;
locs[idx].addr.offset = atoi(token);
nbTokenRead++;
// ZMIN
token = strtok(0, "_");
if(!token)
break;
locs[idx].zmin = osg::asciiToFloat(token);
nbTokenRead++;
// ZMAX
token = strtok(0, "_");
if(!token)
break;
locs[idx].zmax = osg::asciiToFloat(token);
nbTokenRead++;
locs[idx].lod = parentLod+1;
token = strtok(0, "_");
}
if(nbTokenRead != nbChild*6)
return false;
else
return true;
}
std::string ReaderWriterTXP::getArchiveName(const std::string& dir)
{
#ifdef _WIN32
const char _PATHD = '\\';
#elif defined(macintosh)
const char _PATHD = ':';
#else
const char _PATHD = '/';
#endif
return dir+_PATHD+"archive.txp";
}
osg::ref_ptr< TXPArchive > ReaderWriterTXP::getArchive(int id, const std::string& dir)
{
osg::ref_ptr< TXPArchive > archive = NULL;
std::map< int,osg::ref_ptr<TXPArchive> >::iterator iter = _archives.find(id);
if (iter != _archives.end())
{
archive = iter->second.get();
}
else
{
std::string archiveName = getArchiveName(dir);
ReaderWriterTXPERROR("getArchive()") << "archive id " << id << " not found: \"" << archiveName << "\"" << std::endl;
}
return archive;
}
osg::ref_ptr< TXPArchive > ReaderWriterTXP::createArchive(int id, const std::string& dir)
{
std::string archiveName = getArchiveName(dir);
osg::ref_ptr< TXPArchive > archive = getArchive(id, dir);
if (archive != NULL)
{
ReaderWriterTXPERROR("createArchive()") << "archive id " << id << " already exists: \"" << archiveName << "\"" << std::endl;
return NULL;
}
archive = new TXPArchive;
if (archive->openFile(archiveName) == false)
{
ReaderWriterTXPERROR("createArchive()") << "failed to load archive: \"" << archiveName << "\"" << std::endl;
return NULL;
}
if (archive->loadMaterials() == false)
{
ReaderWriterTXPERROR("createArchive()") << "failed to load materials from archive: \"" << archiveName << "\"" << std::endl;
return NULL;
}
if (archive->loadModels() == false)
{
ReaderWriterTXPERROR("createArchive()") << "failed to load models from archive: \"" << archiveName << "\"" << std::endl;
return NULL;
}
if (archive->loadLightAttributes() == false)
{
ReaderWriterTXPERROR("createArchive()") << "failed to load light attributes from archive: \"" << archiveName << "\"" << std::endl;
return NULL;
}
if (archive->loadTextStyles() == false)
{
ReaderWriterTXPERROR("createArchive()") << "failed to load text styles from archive: \"" << archiveName << "\"" << std::endl;
return NULL;
}
archive->setId(id);
_archives[id] = archive;
return archive;
}
bool ReaderWriterTXP::removeArchive( int id )
{
OSG_INFO<<"ReaderWriterTXP::removeArchive(id="<<id<<")"<<std::endl;
//return (_archives.erase(id) >= 1);
bool result=_archives.erase(id) >= 1;
OSG_WARN<<"remove archive " << id << " size " << _archives.size()
<< " result " << result << std::endl;
return result;
}
class SeamFinder: public osg::NodeVisitor
{
public:
SeamFinder(int x, int y, int lod, const TXPArchive::TileInfo& info, TXPArchive *archive ):
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
_x(x), _y(y), _lod(lod), _info(info), _archive(archive)
{}
virtual void apply(osg::Group& group)
{
for (unsigned int i = 0; i < group.getNumChildren(); i++)
{
osg::Node* child = group.getChild(i);
osg::Node* seam = seamReplacement(child);
if (child != seam)
{
group.replaceChild(child,seam);
}
else
{
child->accept(*this);
}
}
}
protected:
osg::Node* seamReplacement(osg::Node* node);
SeamFinder& operator = (const SeamFinder&) { return *this; }
int _x, _y, _lod;
const TXPArchive::TileInfo& _info;
TXPArchive *_archive;
};
#define equalDoubles(a, b) (fabs(a-b) < 0.001)
osg::Node* SeamFinder::seamReplacement(osg::Node* node)
{
osg::Group* group = node->asGroup();
if ( group == 0 )
return node;
std::vector<osg::Node*> nonSeamChildren;
osg::LOD* hiRes = 0;
osg::LOD* loRes = 0;
const trpgHeader* header = _archive->GetHeader();
trpgHeader::trpgTileType tileType;
header->GetTileOriginType(tileType);
for (unsigned int i = 0; i < group->getNumChildren(); i++)
{
osg::LOD* lod = dynamic_cast<osg::LOD*>(group->getChild(i));
if (lod == 0)
{
nonSeamChildren.push_back(group->getChild(i));
continue;
}
bool nonSeamChild = true;
// looks like the problem is in here - likely due to seamLOD info
// not being adjusted properly in tiled databases
// seam center is outside the bounding box of the tile
osg::Vec3 lodCenter = lod->getCenter();
if(tileType == trpgHeader::TileLocal)
{
trpg2dPoint tileExtents;
header->GetTileSize(0, tileExtents);
osg::BoundingBox bbox;
_archive->getExtents(bbox);
osg::Vec3 offset(0.0, 0.0, 0.0);
int divider = (0x1 << _lod);
// calculate which tile model is located in
tileExtents.x /= divider;
tileExtents.y /= divider;
offset[0] = _x*tileExtents.x;// + tileExtents.x*0.5;
offset[1] = _y*tileExtents.y;// + tileExtents.y*0.5;
lodCenter += offset;
}
if (!_info.bbox.contains(lodCenter))
{
const osg::LOD::RangeList& rangeList = lod->getRangeList();
if (!rangeList.size())
{
// TODO: Warn here
continue;
}
TXPArchive::TileInfo lod_plus_one_info;
if (!this->_archive->getTileInfo(_x,_y,_lod+1,lod_plus_one_info))
{
// TODO: Warn here
continue;
}
double lod_plus_oneSwitchInDistance = lod_plus_one_info.maxRange;
double lod0SwitchInDistance = _info.lod0Range;
// low res seam has min/max ranges of lod+1 range/lod 0 range
if (equalDoubles(lod_plus_oneSwitchInDistance,rangeList.at(0).first) && equalDoubles(lod0SwitchInDistance,rangeList.at(0).second))
{
if (loRes==0)
{
loRes = lod;
nonSeamChild = false;
}
}
else
// hi res seam has min/max ranges of 0 range/lod+1 range
if (rangeList.at(0).first==0.0 && equalDoubles(lod_plus_oneSwitchInDistance,rangeList.at(0).second))
{
if (hiRes==0)
{
hiRes = lod;
nonSeamChild = false;
}
}
}
if (nonSeamChild)
{
nonSeamChildren.push_back(lod);
}
}
if (loRes)
{
int dx = 0;
int dy = 0;
int lod = _lod;
osg::Vec3 lodCenter = loRes->getCenter();
if(tileType == trpgHeader::TileLocal)
{
trpg2dPoint tileExtents;
header->GetTileSize(0, tileExtents);
osg::BoundingBox bbox;
_archive->getExtents(bbox);
osg::Vec3 offset(0.0, 0.0, 0.0);
int divider = (0x1 << _lod);
// calculate which tile model is located in
tileExtents.x /= divider;
tileExtents.y /= divider;
offset[0] = _x*tileExtents.x;// + tileExtents.x*0.5;
offset[1] = _y*tileExtents.y;// + tileExtents.y*0.5;
lodCenter += offset;
}
osg::Vec3 delta = lodCenter-_info.center;
if (fabs(delta.x())>fabs(delta.y()))
{
if ( delta.x() < 0.0 )
--dx; // west
else
dx++; // east
}
else
{
if ( delta.y() < 0.0 )
--dy; // south
else
++dy; // north
}
TXPSeamLOD* seam = new TXPSeamLOD(_x, _y, lod, dx, dy);
seam->setCenter(loRes->getCenter());
seam->addChild(loRes->getChild(0)); // low res
if (hiRes)
{
seam->addChild(hiRes->getChild(0)); // high res
}
if (nonSeamChildren.empty())
{
return seam;
}
else
{
osg::Group* newGroup = new osg::Group;
newGroup->addChild(seam);
for (unsigned int i = 0; i < nonSeamChildren.size(); i++)
newGroup->addChild(nonSeamChildren[i]);
return newGroup;
}
}
return node;
}
osg::Node* ReaderWriterTXP::getTileContent(const TXPArchive::TileInfo &info, int x, int y, int lod, TXPArchive* archive, std::vector<TXPArchive::TileLocationInfo>& childrenLoc)
{
if ( archive == 0 )
return 0;
int majorVersion, minorVersion;
archive->GetVersion(majorVersion, minorVersion);
double realMinRange = info.minRange;
double realMaxRange = info.maxRange;
double usedMaxRange = osg::maximum(info.maxRange,1e7);
osg::Vec3 tileCenter;
osg::Group* tileGroup = archive->getTileContent(x,y,lod,realMinRange,realMaxRange,usedMaxRange,tileCenter, childrenLoc);
// if group has only one child, then simply use its child.
// if the node is a transform, then stop processing so as to not loose the transformation
while (tileGroup && !tileGroup->asTransform() &&
tileGroup->getNumChildren()==1 && tileGroup->getChild(0)->asGroup())
{
tileGroup = tileGroup->getChild(0)->asGroup();
}
bool doSeam = false;
if(majorVersion == 2 && minorVersion >= 1)
doSeam = (childrenLoc.size() > 0);
else
doSeam = (lod < (archive->getNumLODs() - 1));
// Handle seams
if (tileGroup && doSeam)
{
SeamFinder sfv(x,y,lod,info,archive);
tileGroup->accept(sfv);
}
return tileGroup;
}
// this version only gets called if the TXP version is >= than 2.1
osg::Node* ReaderWriterTXP::getTileContent(const TXPArchive::TileInfo &info, const TXPArchive::TileLocationInfo& loc, TXPArchive* archive, std::vector<TXPArchive::TileLocationInfo>& childrenLoc)
{
if ( archive == 0 )
return 0;
// int numLods = archive->getNumLODs();
double realMinRange = info.minRange;
double realMaxRange = info.maxRange;
double usedMaxRange = osg::maximum(info.maxRange,1e7);
osg::Vec3 tileCenter;
osg::Group* tileGroup = archive->getTileContent(loc,realMinRange,realMaxRange,usedMaxRange,tileCenter, childrenLoc);
// if group has only one child, then simply use its child.
// if the node is a transform, then stop processing so as to not loose the transformation
while (tileGroup && !tileGroup->asTransform() &&
tileGroup->getNumChildren()==1 && tileGroup->getChild(0)->asGroup())
{
tileGroup = tileGroup->getChild(0)->asGroup();
}
// Handle seams
if (tileGroup && childrenLoc.size() > 0)
{
SeamFinder sfv(loc.x, loc.y, loc.lod, info, archive);
tileGroup->accept(sfv);
}
return tileGroup;
}
REGISTER_OSGPLUGIN(txp, ReaderWriterTXP)