From Terrex and Andrew Sampsom and Don Tidrow and Robert Osfield,
email comments from Andew Sampson, "I've contacted Terrex, and obtained the 2.2 version of their trpage library. The library included a fork of OSG 0.9.8's txp plugin, modified to load 2.1+ txp DBs. I've done the work of incorporating the changes made to OSG's txp plugin since 0.9.8 into Terrex's fork. The forked version is now up-to-date with the changes made to OSG 0.9.9 and 1.0. Terrex made a lot of changes (especially differences in whitespace), so the diff between the forked version and OSG 1.0's txp plugin is yucky. I did my best, but keep in mind that this is the result of a 4-way merge (kinda... terrex-0.9.8, stock-0.9.8, stock-0.9.9, stock-1.0). I really want to see this forked version merged back into the main OSG branch. The new features offered by this version of the plugin (2.1+ support, variable LOD support, bug fixes) are worth the trouble." -- Don Tidrow then took this code and added his work. -- Robert Osfield then fixed all the warnings that abound in the trpage code base.
This commit is contained in:
@@ -3,9 +3,12 @@
|
||||
#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 "ReaderWriterTXP.h"
|
||||
#include "TXPNode.h"
|
||||
@@ -16,6 +19,13 @@
|
||||
|
||||
#define ReaderWriterTXPERROR(s) osg::notify(osg::NOTICE) << "txp::ReaderWriterTXP::" << (s) << " error: "
|
||||
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
char gbuf[2048];
|
||||
}
|
||||
|
||||
using namespace txp;
|
||||
|
||||
int ReaderWriterTXP::_archiveId = 0;
|
||||
@@ -29,7 +39,8 @@ osgDB::ReaderWriter::ReadResult ReaderWriterTXP::local_readNode(const std::strin
|
||||
if (strncmp(name.c_str(),"archive",7)==0)
|
||||
{
|
||||
std::string fileName = osgDB::findDataFile( file, options );
|
||||
if (fileName.empty()) return ReadResult::FILE_NOT_FOUND;
|
||||
if ( fileName.empty() )
|
||||
return ReadResult::FILE_NOT_FOUND;
|
||||
|
||||
osg::ref_ptr<TXPNode> txpNode = new TXPNode;
|
||||
txpNode->setArchiveName(fileName);
|
||||
@@ -45,7 +56,8 @@ osgDB::ReaderWriter::ReadResult ReaderWriterTXP::local_readNode(const std::strin
|
||||
{
|
||||
int id = _archiveId++;
|
||||
archive->setId(id);
|
||||
txpNode->setArchive(getArchive(id,osgDB::getFilePath(fileName)));
|
||||
// txpNode->setArchive(getArchive(id,osgDB::getFilePath(fileName)));
|
||||
getArchive(id,osgDB::getFilePath(fileName));
|
||||
}
|
||||
return txpNode.get();
|
||||
}
|
||||
@@ -56,35 +68,92 @@ osgDB::ReaderWriter::ReadResult ReaderWriterTXP::local_readNode(const std::strin
|
||||
}
|
||||
|
||||
// We load tileLOD_XxY_ID.txp
|
||||
if (strncmp(name.c_str(),"tile",4)==0)
|
||||
else if (strncmp(name.c_str(),"tile",4)==0)
|
||||
{
|
||||
int x,y,lod;
|
||||
unsigned int id;
|
||||
sscanf(name.c_str(),"tile%d_%dx%d_%d",&lod,&x,&y,&id);
|
||||
TXPArchive* archive = getArchive(id,osgDB::getFilePath(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;
|
||||
|
||||
osg::ref_ptr<osg::Node> tileContent = getTileContent(info,x,y,lod,archive);
|
||||
std::vector<TXPArchive::TileLocationInfo> childrenLoc;
|
||||
osg::ref_ptr<osg::Node> tileContent = getTileContent(info,x,y,lod,archive, 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)
|
||||
{
|
||||
char pagedLODfile[1024];
|
||||
sprintf(pagedLODfile,"%s\\subtiles%d_%dx%d_%d.txp",
|
||||
archive->getDir(),
|
||||
lod,
|
||||
x,
|
||||
y,
|
||||
archive->getId()
|
||||
);
|
||||
sprintf(pagedLODfile,"%s\\subtiles%d_%dx%d_%d",
|
||||
archive->getDir(),
|
||||
lod,
|
||||
x,
|
||||
y,
|
||||
archive->getId());
|
||||
|
||||
strcat(pagedLODfile, childrenInfoStr.c_str());
|
||||
strcat(pagedLODfile, ".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;
|
||||
// not use maximum(info.maxRange,1e7) as just maxRange would result in some corner tiles from being culled out.
|
||||
// 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);
|
||||
@@ -110,111 +179,379 @@ osgDB::ReaderWriter::ReadResult ReaderWriterTXP::local_readNode(const std::strin
|
||||
return tileContent.get();
|
||||
}
|
||||
|
||||
// We load subtilesLOD_XxY_ID.txp
|
||||
if (strncmp(name.c_str(),"sub",3)==0)
|
||||
|
||||
// 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;
|
||||
sscanf(name.c_str(),"subtiles%d_%dx%d_%d",&lod,&x,&y,&id);
|
||||
TXPArchive* archive = getArchive(id,osgDB::getFilePath(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();
|
||||
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++)
|
||||
if(majorVersion == 2 && minorVersion >= 1)
|
||||
{
|
||||
for (int iy = 0; iy < 2; iy++)
|
||||
int nbChild;
|
||||
|
||||
sscanf(name.c_str(),"subtiles%d_%dx%d_%d_%d",&lod,&x,&y,&id, &nbChild);
|
||||
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)
|
||||
{
|
||||
int tileX = x*2+ix;
|
||||
int tileY = y*2+iy;
|
||||
int tileLOD = lod+1;
|
||||
ReaderWriterTXPERROR("ReaderWriterTXP::local_readNode()") << "'subtile' filename children parsing failed " << std::endl;
|
||||
return ReadResult::ERROR_IN_READING_FILE;
|
||||
}
|
||||
|
||||
TXPArchive::TileInfo info;
|
||||
if (!archive->getTileInfo(tileX,tileY,tileLOD,info))
|
||||
continue;
|
||||
const trpgHeader* header = archive->GetHeader();
|
||||
trpgHeader::trpgTileType tileType;
|
||||
header->GetTileOriginType(tileType);
|
||||
|
||||
osg::ref_ptr<osg::Node> tileContent = getTileContent(info,tileX,tileY,tileLOD,archive);
|
||||
TXPArchive::TileLocationInfo plInfo;
|
||||
plInfo.x = x;
|
||||
plInfo.y = y;
|
||||
plInfo.lod = lod;
|
||||
TXPArchive::TileInfo parentInfo;
|
||||
archive->getTileInfo(plInfo,parentInfo);
|
||||
|
||||
tileContent->setName("TileContent");
|
||||
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;
|
||||
|
||||
if (tileLOD < (numLods-1))
|
||||
{
|
||||
char pagedLODfile[1024];
|
||||
sprintf(pagedLODfile,"%s\\subtiles%d_%dx%d_%d.txp",
|
||||
archive->getDir(),
|
||||
tileLOD,
|
||||
tileX,
|
||||
tileY,
|
||||
archive->getId()
|
||||
);
|
||||
osg::ref_ptr<osg::Node> tileContent = getTileContent(info, loc, archive, childrenChildLoc);
|
||||
|
||||
osg::ref_ptr<TXPPagedLOD> pagedLOD = new TXPPagedLOD;
|
||||
tileContent->setName("TileContent");
|
||||
|
||||
// not 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(childrenChildLoc.size() > 0)
|
||||
{
|
||||
std::string childInfoStr;
|
||||
createChildrenLocationString(childrenChildLoc, childInfoStr);
|
||||
|
||||
if(tileType == trpgHeader::TileLocal)
|
||||
char pagedLODfile[1024];
|
||||
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::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::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());
|
||||
subtiles->setUserData(new TileIdentifier(loc.x, loc.y, loc.lod)); // is this really needed?
|
||||
}
|
||||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//osg::notify(osg::NOTICE) << "Subtiles for " << x << " " << y << " " << lod << " lodaded" << std::endl;
|
||||
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, childrenLoc);
|
||||
|
||||
tileContent->setName("TileContent");
|
||||
|
||||
if (tileLOD < (numLods-1))
|
||||
{
|
||||
char pagedLODfile[1024];
|
||||
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::notify(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
|
||||
strcpy(gbuf, name.substr(startOfList + 1, endOfList - startOfList - 1).c_str());
|
||||
char *token = strtok( gbuf, "_" );
|
||||
|
||||
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 = (float)atof(token);
|
||||
nbTokenRead++;
|
||||
|
||||
// ZMAX
|
||||
token = strtok(0, "_");
|
||||
if(!token)
|
||||
break;
|
||||
locs[idx].zmax= (float)atof(token);
|
||||
nbTokenRead++;
|
||||
|
||||
locs[idx].lod = parentLod+1;
|
||||
|
||||
|
||||
|
||||
token = strtok(0, "_");
|
||||
}
|
||||
|
||||
if(nbTokenRead != nbChild*6)
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
|
||||
|
||||
}
|
||||
|
||||
TXPArchive *ReaderWriterTXP::getArchive(int id, const std::string& dir)
|
||||
{
|
||||
TXPArchive* archive = NULL;
|
||||
@@ -279,45 +616,50 @@ TXPArchive *ReaderWriterTXP::getArchive(int id, const std::string& dir)
|
||||
class SeamFinder: public osg::NodeVisitor
|
||||
{
|
||||
public:
|
||||
SeamFinder(int x, int y, int lod, TXPArchive::TileInfo& info, TXPArchive *archive ):
|
||||
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
|
||||
_x(x), _y(y), _lod(lod), _info(info), _archive(archive)
|
||||
{};
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
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);
|
||||
|
||||
int _x, _y, _lod;
|
||||
TXPArchive::TileInfo& _info;
|
||||
const TXPArchive::TileInfo& _info;
|
||||
TXPArchive *_archive;
|
||||
};
|
||||
|
||||
osg::Node* SeamFinder::seamReplacement(osg::Node* node)
|
||||
{
|
||||
osg::Group* group = node->asGroup();
|
||||
if (group == 0) return node;
|
||||
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));
|
||||
@@ -329,11 +671,32 @@ osg::Node* SeamFinder::seamReplacement(osg::Node* node)
|
||||
|
||||
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
|
||||
if (!_info.bbox.contains(lod->getCenter()))
|
||||
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))
|
||||
{
|
||||
// seams have center as the neighbour tile
|
||||
osg::Vec3 d = _info.center - lod->getCenter();
|
||||
osg::Vec3 d = _info.center - lodCenter;
|
||||
if (((fabs(d.x())-_info.size.x()) > 0.0001) && ((fabs(d.y())-_info.size.y()) > 0.0001))
|
||||
{
|
||||
nonSeamChildren.push_back(lod);
|
||||
@@ -372,19 +735,43 @@ osg::Node* SeamFinder::seamReplacement(osg::Node* node)
|
||||
int dx = 0;
|
||||
int dy = 0;
|
||||
int lod = _lod;
|
||||
osg::Vec3 delta = loRes->getCenter()-_info.center;
|
||||
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
|
||||
if ( delta.x() < 0.0 )
|
||||
--dx; // west
|
||||
else
|
||||
dx++; // east
|
||||
}
|
||||
else
|
||||
{
|
||||
if (delta.y()<0.0) --dy; // south
|
||||
else ++dy; // north
|
||||
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)
|
||||
{
|
||||
@@ -411,28 +798,34 @@ osg::Node* SeamFinder::seamReplacement(osg::Node* node)
|
||||
return node;
|
||||
}
|
||||
|
||||
osg::Node* ReaderWriterTXP::getTileContent(TXPArchive::TileInfo &info, int x, int y, int lod, TXPArchive* archive)
|
||||
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 false;
|
||||
if ( archive == 0 )
|
||||
return false;
|
||||
|
||||
int numLods = archive->getNumLODs();
|
||||
int majorVersion, minorVersion;
|
||||
archive->GetVersion(majorVersion, minorVersion);
|
||||
|
||||
double realMinRange = info.minRange;
|
||||
double realMaxRange = info.maxRange;
|
||||
double usedMaxRange = osg::maximum(info.maxRange,1e7);
|
||||
double usedMaxRange = osg::maximum(info.maxRange,1e7);
|
||||
osg::Vec3 tileCenter;
|
||||
osg::Group* tileGroup = archive->getTileContent(x,y,lod,realMinRange,realMaxRange,usedMaxRange,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 1
|
||||
while (tileGroup->getNumChildren()==1 && tileGroup->getChild(0)->asGroup())
|
||||
{
|
||||
tileGroup = tileGroup->getChild(0)->asGroup();
|
||||
}
|
||||
#endif
|
||||
|
||||
bool doSeam = false;
|
||||
if(majorVersion == 2 && minorVersion >= 1)
|
||||
doSeam = (childrenLoc.size() > 0);
|
||||
else
|
||||
doSeam = (lod < (archive->getNumLODs() - 1));
|
||||
|
||||
// Handle seams
|
||||
if (lod < (numLods-1))
|
||||
if (doSeam)
|
||||
{
|
||||
SeamFinder sfv(x,y,lod,info,archive);
|
||||
tileGroup->accept(sfv);
|
||||
@@ -441,5 +834,35 @@ osg::Node* ReaderWriterTXP::getTileContent(TXPArchive::TileInfo &info, int x, in
|
||||
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 false;
|
||||
|
||||
// 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.
|
||||
while (tileGroup->getNumChildren()==1 && tileGroup->getChild(0)->asGroup())
|
||||
{
|
||||
tileGroup = tileGroup->getChild(0)->asGroup();
|
||||
}
|
||||
|
||||
// Handle seams
|
||||
if (childrenLoc.size() > 0)
|
||||
{
|
||||
SeamFinder sfv(loc.x, loc.y, loc.lod, info, archive);
|
||||
tileGroup->accept(sfv);
|
||||
}
|
||||
|
||||
return tileGroup;
|
||||
}
|
||||
|
||||
osgDB::RegisterReaderWriterProxy<ReaderWriterTXP> g_txpReaderWriterProxy;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user