#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "TXPParser.h" #include "TXPArchive.h" using namespace txp; #include static osg::ApplicationUsageProxy TXP_e0(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_TXP_DEFAULT_MAX_ANISOTROPY \" []\"","1.0 | 2.0 | 4.0 | 8.0 | 16.0"); class LayerGroup : public osg::Group { public: LayerGroup() : osg::Group() {} LayerGroup(const LayerGroup& gg,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY): osg::Group(gg, copyop) {}; META_Node(txp, LayerGroup); protected: virtual ~LayerGroup() {} }; class LayerVisitor : public osg::NodeVisitor { public: LayerVisitor():osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {} virtual void apply(osg::Group& node) { LayerGroup *lg = dynamic_cast(&node); if (lg) { for (unsigned int i=1; i < lg->getNumChildren(); ++i) { osg::Node *child = lg->getChild(i); osg::StateSet *sset = child->getOrCreateStateSet(); osg::PolygonOffset* polyoffset = new osg::PolygonOffset; polyoffset->setFactor(-1.0f); polyoffset->setUnits(-200.0f*i); sset->setAttributeAndModes(polyoffset,osg::StateAttribute::ON); } } traverse(node); } }; TXPParser::TXPParser(): _archive(0), _currentTop(0), _root(0), _underBillboardSubgraph(false), _numBillboardLevels(0), _underLayerSubgraph(false), _numLayerLevels(0), _layerGeode(0), _defaultMaxAnisotropy(1.0f), _realMinRange(0.0), _realMaxRange(0.0), _usedMaxRange(0.0), _childRefCB(0) { AddCallback(TRPG_ATTACH, new attachRead(this)); AddCallback(TRPG_CHILDREF, new childRefRead(this)); AddCallback(TRPG_GEOMETRY, new geomRead(this)); AddCallback(TRPG_GROUP, new groupRead(this)); AddCallback(TRPG_LOD, new lodRead(this)); AddCallback(TRPG_MODELREF, new modelRefRead(this)); AddCallback(TRPG_BILLBOARD, new billboardRead(this)); AddCallback(TRPG_LIGHT, new lightRead(this)); AddCallback(TRPG_LAYER, new layerRead(this)); AddCallback(TRPG_LABEL, new labelRead(this)); AddCallback(TRPGTILEHEADER, new tileHeaderRead(this)); _childRefCB = dynamic_cast(GetCallback(TRPG_CHILDREF)); if (getenv("OSG_TXP_DEFAULT_MAX_ANISOTROPY")) { _defaultMaxAnisotropy = atof(getenv("OSG_TXP_DEFAULT_MAX_ANISOTROPY")); } } TXPParser::~TXPParser() { } osg::Group *TXPParser::parseScene( trpgReadBuffer &buf, std::map > &materials, std::map > &models, double realMinRange, double realMaxRange, double usedMaxRange) { if (_archive == 0) return NULL; if(_childRefCB) _childRefCB->Reset(); _root = new osg::Group(); _currentTop = _root.get(); _materialMap = &materials; _localMaterials.clear(); _models = ⊧ _underBillboardSubgraph = false; _numBillboardLevels = 0; _underLayerSubgraph = false; _numLayerLevels = 0; _realMinRange = realMinRange; _realMaxRange = realMaxRange; _usedMaxRange = usedMaxRange; _tileCenter = osg::Vec3(0.f,0.f,0.f); if (!Parse(buf)) { osg::notify(osg::NOTICE) << "txp::TXPParser::parseScene(): failed to parse the given tile" << std::endl; return NULL; } for (std::map::iterator i = _tileGroups.begin(); i != _tileGroups.end(); i++) { replaceTileLod((*i).first); } _tileGroups.clear(); LayerVisitor lv; _root->accept(lv); return _root.get(); } void TXPParser::replaceTileLod(osg::Group* group) { if (group->getNumChildren() == 2) { osg::LOD* loLOD = dynamic_cast(group->getChild(0)); osg::LOD* hiLOD = dynamic_cast(group->getChild(1)); if (loLOD && hiLOD) { osg::Group *g = dynamic_cast(hiLOD->getChild(0)); if (!g) return; if (g->getNumChildren()) return; _tileCenter = loLOD->getCenter(); group->addChild(loLOD->getChild(0)); group->removeChild(loLOD); group->removeChild(hiLOD); } } } unsigned int TXPParser::GetNbChildrenRef() const { if(_childRefCB) return _childRefCB->GetNbChildrenRef(); else return 0; } const trpgChildRef* TXPParser::GetChildRef(unsigned int idx) const { if(_childRefCB) return _childRefCB->GetChildRef(idx); else return 0; } bool TXPParser::StartChildren(void * /*in*/) { bool pushParent = true; if (_underBillboardSubgraph ) { if (_numBillboardLevels > 0) pushParent = false; _numBillboardLevels++; } else if (_underLayerSubgraph) { if (_numLayerLevels > 0) pushParent = false; _numLayerLevels++; } if (pushParent) { _parents.push(_currentTop); _currentTop = _currentNode->asGroup(); } return true; } bool TXPParser::EndChildren(void *) { bool popParent = true; if (_underLayerSubgraph) { _numLayerLevels--; if (_numLayerLevels == 0) { _underLayerSubgraph = false; } else popParent = false; } else if (_underBillboardSubgraph) { _numBillboardLevels--; if (_numBillboardLevels == 0) { _underBillboardSubgraph = false; } else popParent = false; } if (popParent) { if (_parents.size()) { _currentTop = _parents.top(); _parents.pop(); } else _currentTop = _root.get(); } return true; } DeferredLightAttribute& TXPParser::getLightAttribute(int ix) { return _archive->getLightAttribute(ix); } class FindEmptyGroupsVisitor : public osg::NodeVisitor { public: FindEmptyGroupsVisitor(osg::NodeList& nl): osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN), _nl(nl) {}; virtual void apply(osg::Group& group) { if (group.getNumChildren()==0) { _nl.push_back(&group); } traverse(group); } protected: osg::NodeList& _nl; }; void TXPParser::removeEmptyGroups() { if (_root.get() && _root->getNumChildren()) { osg::NodeList nl; FindEmptyGroupsVisitor fegv(nl); _root->accept(fegv); for (unsigned int i = 0; i < nl.size(); i++) { osg::Node* node = nl[i].get(); if (node == NULL) continue; osg::Node::ParentList parents = node->getParents(); for (unsigned int j = 0; j < parents.size(); j++) { osg::Group* parent = parents[j]; if (parent) parent->removeChild(node); } } } } osg::Geode* TXPParser::createBoundingBox(int x,int y, int lod) { TXPArchive::TileInfo info; _archive->getTileInfo(x,y,lod,info); osg::Geode* geode = new osg::Geode(); osg::TessellationHints* hints = new osg::TessellationHints; hints->setDetailRatio(0.5f); osg::ShapeDrawable* sd = new osg::ShapeDrawable( new osg::Box( info.center, info.bbox.xMax()-info.bbox.xMin(), info.bbox.yMax()-info.bbox.yMin(), 1 ), hints ); if (lod==0) { sd->setColor(osg::Vec4(1.0f,1.0f,1.0f,1.0f)); } else if (lod==1) { sd->setColor(osg::Vec4(1.0f,0.0f,0.0f,1.0f)); } else if (lod==2) { sd->setColor(osg::Vec4(0.0f,1.0f,0.0f,1.0f)); } else if (lod==3) { sd->setColor(osg::Vec4(0.0f,0.0f,1.0f,1.0f)); } else if (lod==4) { sd->setColor(osg::Vec4(0.0f,0.0f,0.0f,1.0f)); } geode->addDrawable( sd ); return geode; } void TXPParser::loadLocalMaterials() { bool separateGeo = false; int majorVer,minorVer; this->getArchive()->GetVersion(majorVer,minorVer); if((majorVer >= TRPG_NOMERGE_VERSION_MAJOR) && (minorVer>=TRPG_NOMERGE_VERSION_MINOR)) { separateGeo = true; } // new to 2.0 LOCAL materials trpgrImageHelper image_helper( _archive->GetEndian(), _archive->getDir(), *_archive->GetMaterialTable(), *_archive->GetTexTable(), separateGeo ); trpgTileHeader* tile_head = getTileHeaderRef(); int n_materials; tile_head->GetNumLocalMaterial(n_materials); int n_mat; tile_head->GetNumMaterial(n_mat); _localMaterials.clear(); _localMaterials.resize(n_materials); { for (int i = 0; i < n_materials; i++) { osg::StateSet* osg_state_set = new osg::StateSet; trpgLocalMaterial locmat; tile_head->GetLocalMaterial(i,locmat); const trpgMaterial* mat = 0; const trpgTexture *tex = 0; int32 size; image_helper.GetImageInfoForLocalMat(&locmat, &mat,&tex,size); int num_tex; mat->GetNumTexture(num_tex); for (int texNo = 0 ; texNo < num_tex; ++texNo) { int texId; trpgTextureEnv texEnv; mat->GetTexture(texNo,texId,texEnv); // Set up texture environment osg::TexEnv *osg_texenv = new osg::TexEnv(); int32 te_mode; texEnv.GetEnvMode(te_mode); switch( te_mode ) { case trpgTextureEnv::Alpha : osg_texenv->setMode(osg::TexEnv::REPLACE); break; case trpgTextureEnv::Decal: osg_texenv->setMode(osg::TexEnv::DECAL); break; case trpgTextureEnv::Blend : osg_texenv->setMode(osg::TexEnv::BLEND); break; case trpgTextureEnv::Modulate : osg_texenv->setMode(osg::TexEnv::MODULATE); break; } osg_state_set->setTextureAttribute(texNo,osg_texenv); image_helper.GetNthImageInfoForLocalMat(&locmat, texNo, &mat,&tex,size); trpgTexture::ImageMode mode; tex->GetImageMode(mode); osg::Texture2D* osg_texture = 0L; if(mode == trpgTexture::Template) osg_texture = getTemplateTexture(image_helper,&locmat, tex, texNo); else if(mode == trpgTexture::Local) osg_texture = getLocalTexture(image_helper,tex); else if(mode == trpgTexture::Global) osg_texture = _archive->getGlobalTexture(texId); if(osg_texture) { if(osg_texture->getImage()) { GLenum gltype = osg_texture->getImage()->getPixelFormat(); if( gltype == GL_RGBA || gltype == GL_LUMINANCE_ALPHA ) { osg_state_set->setMode(GL_BLEND,osg::StateAttribute::ON); osg_state_set->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); } } else { osg::notify(osg::WARN) << "No image\n"; } osg_state_set->setTextureAttributeAndModes(texNo,osg_texture, osg::StateAttribute::ON); int wrap_s, wrap_t; texEnv.GetWrap(wrap_s, wrap_t); osg_texture->setWrap(osg::Texture2D::WRAP_S, wrap_s == trpgTextureEnv::Repeat ? osg::Texture2D::REPEAT: osg::Texture2D::CLAMP_TO_EDGE ); osg_texture->setWrap(osg::Texture2D::WRAP_T, wrap_t == trpgTextureEnv::Repeat ? osg::Texture2D::REPEAT: osg::Texture2D::CLAMP_TO_EDGE ); // by default is anisotropic filtering. osg_texture->setMaxAnisotropy(_defaultMaxAnisotropy); } else { osg::notify(osg::WARN) << "No texture\n"; } } osg::Material *osg_material = new osg::Material; float64 alpha; mat->GetAlpha(alpha); trpgColor color; mat->GetAmbient(color); osg_material->setAmbient( osg::Material::FRONT_AND_BACK , osg::Vec4(color.red, color.green, color.blue, alpha)); mat->GetDiffuse(color); osg_material->setDiffuse(osg::Material::FRONT_AND_BACK , osg::Vec4(color.red, color.green, color.blue, alpha)); mat->GetSpecular(color); osg_material->setSpecular(osg::Material::FRONT_AND_BACK , osg::Vec4(color.red, color.green, color.blue, alpha)); mat->GetEmission(color); osg_material->setEmission(osg::Material::FRONT_AND_BACK , osg::Vec4(color.red, color.green, color.blue, alpha)); float64 shinines; mat->GetShininess(shinines); osg_material->setShininess(osg::Material::FRONT_AND_BACK , (float)shinines); osg_material->setAlpha(osg::Material::FRONT_AND_BACK ,(float)alpha); osg_state_set->setAttributeAndModes(osg_material, osg::StateAttribute::ON); if( alpha < 1.0f ) { osg_state_set->setMode(GL_BLEND,osg::StateAttribute::ON); osg_state_set->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); } /* This controls what alpha values in a texture mean. It can take the values: None,Always,Equal,GreaterThanOrEqual,GreaterThan, LessThanOrEqual,LessThan,Never,NotEqual */ int alphaFunc; mat->GetAlphaFunc(alphaFunc); if( alphaFunc>=GL_NEVER && alphaFunc<=GL_ALWAYS) { float64 ref; mat->GetAlphaRef(ref); osg::AlphaFunc *osg_alpha_func = new osg::AlphaFunc; osg_alpha_func->setFunction((osg::AlphaFunc::ComparisonFunction)alphaFunc,(float)ref); osg_state_set->setAttributeAndModes(osg_alpha_func, osg::StateAttribute::ON); } int cullMode; mat->GetCullMode(cullMode); // Culling mode in txp means opposite from osg i.e. Front-> show front face if( cullMode != trpgMaterial::FrontAndBack) { osg::CullFace* cull_face = new osg::CullFace; switch (cullMode) { case trpgMaterial::Front: cull_face->setMode(osg::CullFace::BACK); break; case trpgMaterial::Back: cull_face->setMode(osg::CullFace::FRONT); break; } osg_state_set->setAttributeAndModes(cull_face, osg::StateAttribute::ON); } _localMaterials[i] = osg_state_set; } } } bool TXPParser::requestModel(int ix) { return _archive->loadModel(ix); } //---------------------------------------------------------------------------- // // LOD Reader Class // //---------------------------------------------------------------------------- void* lodRead::Parse(trpgToken /*tok*/,trpgReadBuffer &buf) { trpgLod lod; if (!lod.Read(buf)) return NULL; // Pull out the LOD data we'll need trpg3dPoint center; lod.GetCenter(center); double in,out,width; lod.GetLOD(in,out,width); double minRange = MIN(in,out); double maxRange = MAX(in,out+width); // Create a new osg LOD osg::ref_ptr osgLod = new osg::LOD(); osg::ref_ptr osgLodG = new GeodeGroup; osgLod->addChild(osgLodG.get()); osg::Vec3 osgCenter; osgCenter[0] = center.x; osgCenter[1] = center.y; osgCenter[2] = center.z; osgLod->setCenter(osgCenter); #if 1 osgLod->setRange(0,minRange, maxRange ); #else osgLod->setRange( 0, _parse->checkAndGetMinRange(minRange), _parse->checkAndGetMaxRange(maxRange) ); #endif // Our LODs are binary so we need to add a group under this LOD and attach stuff // to that instead of the LOD // Add it into the scene graph _parse->setCurrentNode(osgLodG.get()); _parse->getCurrTop()->addChild(osgLod.get()); _parse->setPotentionalTileGroup(_parse->getCurrTop()); return (void*)1; } //---------------------------------------------------------------------------- // // Tile Header Reader Class // //---------------------------------------------------------------------------- void* tileHeaderRead::Parse(trpgToken /*tok*/,trpgReadBuffer &buf) { trpgTileHeader *tileHead = _parse->getTileHeaderRef(); if (!tileHead->Read(buf)) return NULL; _parse->loadLocalMaterials(); return (void *) 1; } //---------------------------------------------------------------------------- // // Model Reference Reader Class // //---------------------------------------------------------------------------- void *modelRefRead::Parse(trpgToken /*tok*/,trpgReadBuffer &buf) { trpgModelRef model; if (!model.Read(buf)) return NULL; // Get the matrix and pfNode for the model int modelID; model.GetModel(modelID); float64 mat[16]; model.GetMatrix(mat); osg::Matrix osg_Mat( (float)mat[0], (float)mat[1], (float)mat[2], (float)mat[3], (float)mat[4], (float)mat[5], (float)mat[6], (float)mat[7], (float)mat[8], (float)mat[9], (float)mat[10],(float)mat[11], (float)mat[12],(float)mat[13],(float)mat[14],(float)mat[15] ); // Note: Array check before you do this osg::Node *osg_Model = NULL; std::map >*modelList = _parse->getModels(); //if( modelList->size() ) { osg_Model = (*modelList)[modelID].get(); if (osg_Model==NULL) { _parse->requestModel(modelID); osg_Model = (*modelList)[modelID].get(); } // Create the SCS and position the model if (osg_Model) { osg::MatrixTransform *scs = new osg::MatrixTransform(); scs->setMatrix(osg_Mat); scs->addChild(osg_Model); // Add the SCS to the hierarchy _parse->setCurrentNode(scs); _parse->getCurrTop()->addChild(scs); } } return (void *) 1; } //---------------------------------------------------------------------------- // // Billboard Reader Class // //---------------------------------------------------------------------------- void* billboardRead::Parse(trpgToken /*tok*/,trpgReadBuffer &buf) { // Read in the txp billboard trpgBillboard bill; if (!bill.Read(buf)) return NULL; if (_parse->underBillboardSubgraph()) { // we don't allow anything under a billboard except geometry osg::notify(osg::WARN) << "TerraPage loader: can only have geometry nodes beneath a billboard.\n"; } else { GeodeGroup* grp = new GeodeGroup; _parse->setCurrentNode(grp); _parse->getCurrTop()->addChild(grp); TXPParser::TXPBillboardInfo info; if (bill.GetType(info.type) && bill.GetMode(info.mode) && bill.GetCenter(info.center) && bill.GetAxis(info.axis)) { // save this state for processing of the geometry node(s) _parse->setLastBillboardInfo(info); _parse->setUnderBillboardSubgraph(true); } } return (void *)1; } //---------------------------------------------------------------------------- // // Group Reader Class // //---------------------------------------------------------------------------- void* groupRead::Parse(trpgToken /*tok*/,trpgReadBuffer &buf) { trpgGroup group; if (!group.Read(buf)) return NULL; if (_parse->underLayerSubgraph()) return (void*)1; osg::ref_ptr osgGroup = new GeodeGroup(); _parse->setCurrentNode(osgGroup.get()); _parse->getCurrTop()->addChild(osgGroup.get()); return (void*)1; } //---------------------------------------------------------------------------- // // Attach Reader Class // //---------------------------------------------------------------------------- void* attachRead::Parse(trpgToken /*tok*/,trpgReadBuffer &buf) { trpgAttach group; if (!group.Read(buf)) return NULL; // Create a new group osg::ref_ptr osgGroup = new osg::Group(); _parse->setCurrentNode(osgGroup.get()); _parse->getCurrTop()->addChild(osgGroup.get()); return (void*)1; } void* childRefRead::Parse(trpgToken /*tok*/,trpgReadBuffer &buf) { // This object contribute nothing to the scenegraph, except // where the children tile should connect. // It only contain location info of the children tile childRefList.push_back(trpgChildRef()); trpgReadWriteable& obj = childRefList.back(); if(obj.Read(buf)) return &obj; else return 0; } void childRefRead::Reset() { childRefList.clear(); } //---------------------------------------------------------------------------- // // light Reader Class // //---------------------------------------------------------------------------- void* lightRead::Parse(trpgToken /*tok*/,trpgReadBuffer &buf) { trpgLight light; if (!light.Read(buf)) return NULL; int attr_index; light.GetAttrIndex(attr_index); uint32 nvert; light.GetNumVertices(nvert); const trpgLightTable *lt = _parse->getArchive()->GetLightTable(); trpgLightAttr *ref = const_cast(lt->GetLightAttrRef(attr_index)); if (!ref) { osg::notify(osg::NOTICE) << "NULL LightAttr " << attr_index << std::endl; return (void*)1; } osgSim::LightPointNode *lpNode = new osgSim::LightPointNode(); trpgColor col; ref->GetFrontColor(col); float64 inten; ref->GetFrontIntensity(inten); trpgLightAttr::PerformerAttr perfAttr; ref->GetPerformerAttr(perfAttr); lpNode->setMaxPixelSize(perfAttr.maxPixelSize); lpNode->setMinPixelSize(perfAttr.minPixelSize); trpg3dPoint norm; ref->GetNormal(norm); trpgLightAttr::LightDirectionality direc; ref->GetDirectionality(direc); for ( unsigned i=0; i < nvert; i++ ) { trpg3dPoint pt; light.GetVertex(i, pt); osgSim::LightPoint lp( true, osg::Vec3(pt.x,pt.y,pt.z), osg::Vec4(col.red, col.green,col.blue, 1.0), inten ); switch (direc) { case trpgLightAttr::trpg_Unidirectional: { float lobeVert=0.f, lobeHorz=0.f, lobeRoll=0.f; float64 tmp; ref->GetHLobeAngle(tmp); lobeHorz = osg::DegreesToRadians( tmp ); ref->GetVLobeAngle(tmp); lobeVert = osg::DegreesToRadians( tmp ); ref->GetLobeRollAngle(tmp); lobeRoll = osg::DegreesToRadians( tmp ); osg::Vec3 normal(norm.x,norm.y,norm.z); lp._sector = new osgSim::DirectionalSector( normal, lobeHorz, lobeVert, lobeRoll ); } break; case trpgLightAttr::trpg_Bidirectional: { float lobeVert=0.f, lobeHorz=0.f, lobeRoll=0.f; float64 tmp; ref->GetHLobeAngle(tmp); lobeHorz = osg::DegreesToRadians( tmp ); ref->GetVLobeAngle(tmp); lobeVert = osg::DegreesToRadians( tmp ); ref->GetLobeRollAngle(tmp); lobeRoll = osg::DegreesToRadians( tmp ); osg::Vec3 normal(norm.x,norm.y,norm.z); lp._sector = new osgSim::DirectionalSector( normal, lobeHorz, lobeVert, lobeRoll ); ref->GetBackColor(col); ref->GetBackIntensity(inten); osgSim::LightPoint lp2( true, osg::Vec3(pt.x,pt.y,pt.z), osg::Vec4(col.red, col.green,col.blue, 1.0), inten ); lp2._sector = new osgSim::DirectionalSector( -normal, lobeHorz, lobeVert, lobeRoll ); lpNode->addLightPoint( lp2 ); } break; default: ; } lpNode->addLightPoint( lp); } _parse->setCurrentNode(lpNode); _parse->getCurrTop()->addChild(lpNode); #if 0 DefferedLightAttribute& dla = _parse->getLightAttribute(attr_index); osgSim::LightPointNode* node = dla.lightPoint.get(); uint32 nvert; light.GetNumVertices(nvert); if( node->getLightPoint(0)._sector.valid() ) // osgSim::LightPoint is a must { for(unsigned int i = 0; i < nvert; i++) { trpg3dPoint pt; light.GetVertex(i, pt); osg::Matrix matrix; // matrix.makeTranslate(pt.x,pt.y,pt.z); matrix.makeRotate(osg::Quat(0.0,dla.attitude)); matrix.setTrans(pt.x,pt.y,pt.z); osg::ref_ptr trans = new osg::MatrixTransform(); trans->setMatrix(matrix); trans->addChild(node); _parse->setCurrentNode(trans.get()); _parse->getCurrTop()->addChild(trans.get()); } } else { //Fall back to osg::Points osg::Vec3Array* vertices = new osg::Vec3Array(nvert); osg::Vec4Array* colors = new osg::Vec4Array(nvert); for(unsigned int i = 0; i < nvert; i++) { trpg3dPoint pt; light.GetVertex(i, pt); (*vertices)[i] = osg::Vec3(pt.x,pt.y,pt.z); (*colors)[i] = node->getLightPoint(0)._color; } osg::ref_ptr geom = new osg::Geometry(); geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::POINTS,0,nvert)); geom->setVertexArray(vertices); geom->setColorArray(colors); geom->setColorBinding(osg::Geometry::BIND_PER_VERTEX); geom->setUseDisplayList(false); geom->setStateSet(dla.fallback.get()); osg::Geode* g = new osg::Geode; g->addDrawable(geom.get()); _parse->setCurrentNode(g); _parse->getCurrTop()->addChild(g); } #endif return (void *) 1; } //---------------------------------------------------------------------------- // // Layer Reader Class // //---------------------------------------------------------------------------- void* layerRead::Parse(trpgToken /*tok*/,trpgReadBuffer &buf) { trpgLayer group; if (!group.Read(buf)) return NULL; osg::ref_ptr osgGroup = new LayerGroup(); _parse->setCurrentNode(osgGroup.get()); _parse->getCurrTop()->addChild(osgGroup.get()); return (void*)1; #if 0 osg::Group* osgGroup = new osg::Group; _parse->setCurrentNode(osgGroup); _parse->getCurrTop()->addChild(osgGroup); _parse->addLayer(osgGroup); return (void*)1; #else if (_parse->underLayerSubgraph()) return (void*)1; osg::ref_ptr layer = new GeodeGroup; _parse->setLayerGeode(layer->getGeode()); _parse->setUnderLayerSubgraph(true); _parse->setCurrentNode(layer.get()); _parse->getCurrTop()->addChild(layer.get()); return (void *)1; #endif } //---------------------------------------------------------------------------- // // Label Reader Class // //---------------------------------------------------------------------------- void* labelRead::Parse(trpgToken /*tok*/,trpgReadBuffer &buf) { trpgLabel label; if (!label.Read(buf)) return NULL; const std::string *labelText = label.GetText(); if (!labelText) return (void*)1; osg::Vec3 pos(label.GetLocation().x, label.GetLocation().y, label.GetLocation().z); osg::ref_ptr< osg::Geode > textGeode = new osg::Geode; osg::ref_ptr< osgText::Text > text = new osgText::Text; // Text std::ostringstream os; std::string::size_type nl; std::string lb = *labelText; while ( (nl=lb.find_first_of('\\')) != std::string::npos) { std::string sub = lb.substr(0,nl); switch (lb[nl+1]) { case 'n': lb.erase(0,nl+2); if (sub.length()) os << sub << std::endl; break; case 't': lb.erase(0,nl+2); os << sub << " ";//'\t'; break; default: lb.erase(0,nl+1); os << '\\' << sub; break; } } if (lb.length()) os << lb; text->setText(os.str()); // Position text->setPosition(pos); // Alignment switch (label.GetAlignment()) { case trpgLabel::Left: text->setAlignment(osgText::Text::LEFT_BOTTOM); break; case trpgLabel::Right: text->setAlignment(osgText::Text::RIGHT_BOTTOM); break; default: text->setAlignment(osgText::Text::CENTER_BOTTOM); } // Axis alignment text->setAxisAlignment(osgText::Text::XZ_PLANE); const trpgLabelPropertyTable *labelPropertyTable = _parse->getArchive()->GetLabelPropertyTable(); const trpgLabelProperty *labelProperty = labelPropertyTable ? labelPropertyTable->GetPropertyRef(label.GetProperty()) : 0; bool addTextGeodeIntoSceneGraph = true; if (labelProperty) { const trpgTextStyleTable *textStyleTable = _parse->getArchive()->GetTextStyleTable(); if (!textStyleTable) return (void*)1; const trpgTextStyle *textStyle = textStyleTable->GetStyleRef(labelProperty->GetFontStyle()); if (!textStyle) return (void*)1; // Size text->setCharacterSize(textStyle->GetCharacterSize()*label.GetScale()*2); text->setCharacterSizeMode(osgText::Text::OBJECT_COORDS); // Font text->setFont(_parse->getArchive()->getStyles()[labelProperty->GetFontStyle()].get()); // Color text->setColor(_parse->getArchive()->getTextColors()[labelProperty->GetFontStyle()]); // Cube osg::ref_ptr cube = 0; // Type switch (labelProperty->GetType()) { case trpgLabelProperty::Billboard: text->setAxisAlignment(osgText::Text::XY_PLANE); text->setAutoRotateToScreen(true); break; case trpgLabelProperty::VertBillboard: addTextGeodeIntoSceneGraph = false; { osg::ref_ptr< osg::Billboard > billboard = new osg::Billboard; text->setPosition(osg::Vec3(0.f,0.f,0.f)); billboard->addDrawable(text.get()); billboard->setAxis(osg::Vec3(0.0f,0.0,1.0f) ); billboard->setNormal(osg::Vec3(0.0f,-1.0,0.0f)); billboard->setMode(osg::Billboard::AXIAL_ROT); billboard->setPosition(0,pos); _parse->getCurrTop()->addChild(billboard.get()); } break; case trpgLabelProperty::Cube: addTextGeodeIntoSceneGraph = false; { osg::Group* group = new osg::Group; osg::BoundingBox box = text->getBound(); float shift = box.radius()+1.f; // front text->setAlignment(osgText::Text::CENTER_CENTER); // back osg::ref_ptr backText = new osgText::Text(*text); backText->setPosition(osg::Vec3(pos.x(),pos.y()+shift,pos.z())); backText->setAxisAlignment(osgText::Text::REVERSED_XZ_PLANE); // top osg::ref_ptr topText = new osgText::Text(*text); topText->setPosition(osg::Vec3(pos.x(),pos.y(),pos.z()+shift)); topText->setAxisAlignment(osgText::Text::XY_PLANE); // bottom osg::ref_ptr bottomText = new osgText::Text(*text); bottomText->setPosition(osg::Vec3(pos.x(),pos.y(),pos.z()-shift)); bottomText->setAxisAlignment(osgText::Text::REVERSED_XY_PLANE); // left osg::ref_ptr leftText = new osgText::Text(*text); leftText->setPosition(osg::Vec3(pos.x()-shift,pos.y(),pos.z())); leftText->setAxisAlignment(osgText::Text::REVERSED_YZ_PLANE); // right osg::ref_ptr rightText = new osgText::Text(*text); rightText->setPosition(osg::Vec3(pos.x()+shift,pos.y(),pos.z())); rightText->setAxisAlignment(osgText::Text::YZ_PLANE); text->setPosition(osg::Vec3(pos.x(),pos.y()-shift,pos.z())); osg::TessellationHints* hints = new osg::TessellationHints; hints->setDetailRatio(0.5f); cube = new osg::ShapeDrawable(new osg::Box(pos,2*shift),hints); osg::ref_ptr polyoffset = new osg::PolygonOffset; polyoffset->setFactor(10.0f); polyoffset->setUnits(10.0f); osg::ref_ptr ss = cube->getOrCreateStateSet(); ss->setAttributeAndModes(polyoffset.get(),osg::StateAttribute::ON); cube->setStateSet(ss.get()); textGeode->addDrawable(cube.get()); textGeode->addDrawable(text.get()); textGeode->addDrawable(backText.get()); textGeode->addDrawable(topText.get()); textGeode->addDrawable(bottomText.get()); textGeode->addDrawable(leftText.get()); textGeode->addDrawable(rightText.get()); group->addChild(textGeode.get()); _parse->getCurrTop()->addChild(group); } break; default: break; } const std::vector *supports = label.GetSupports(); if (supports && supports->size()) { osg::ref_ptr supGeode = new osg::Geode; int supId = labelProperty->GetSupport(); const trpgSupportStyleTable *supTable = _parse->getArchive()->GetSupportStyleTable(); const trpgSupportStyle *supStyle = supTable ? supTable->GetStyleRef(supId) : 0; if (supStyle) { int matId = supStyle->GetMaterial(); osg::Vec4 supLineColor(1.f,1.f,1.f,1.f); _parse->loadMaterial(matId); osg::ref_ptr sset = (*_parse->getMaterials())[matId]; if (cube.get()) { osg::StateSet* ss = cube->getOrCreateStateSet(); ss->merge(*sset); } const trpgMatTable* matTable = _parse->getArchive()->GetMaterialTable(); if (matTable) { const trpgMaterial* mat = matTable->GetMaterialRef(0,matId); if (mat) { trpgColor faceColor; mat->GetColor(faceColor); float64 alpha; mat->GetAlpha(alpha); supLineColor = osg::Vec4(faceColor.red, faceColor.green, faceColor.blue, alpha ); } } switch (supStyle->GetType()) { case trpgSupportStyle::Line: { osg::Geometry* linesGeom = new osg::Geometry(); osg::Vec3Array* vertices = new osg::Vec3Array(supports->size()*2); int cnt = 0; for (unsigned int i = 0; i < supports->size(); i++) { const trpg3dPoint& supPt = (*supports)[i]; (*vertices)[cnt++].set(pos); (*vertices)[cnt++].set(osg::Vec3(supPt.x,supPt.y,supPt.z)); } linesGeom->setVertexArray(vertices); osg::Vec4Array* colors = new osg::Vec4Array; colors->push_back(supLineColor); linesGeom->setColorArray(colors); linesGeom->setColorBinding(osg::Geometry::BIND_OVERALL); osg::Vec3Array* normals = new osg::Vec3Array; normals->push_back(osg::Vec3(0.0f,-1.0f,0.0f)); linesGeom->setNormalArray(normals); linesGeom->setNormalBinding(osg::Geometry::BIND_OVERALL); linesGeom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINES,0,supports->size()*2)); supGeode->addDrawable(linesGeom); } _parse->getCurrTop()->addChild(supGeode.get()); break; case trpgSupportStyle::Cylinder: { osg::ref_ptr hints = new osg::TessellationHints; hints->setDetailRatio(0.5f); for (unsigned int i = 0; i < supports->size(); i++) { const trpg3dPoint& supPt = (*supports)[i]; osg::Vec3 supPos(supPt.x,supPt.y,supPt.z); osg::Vec3 supCenter = (supPos+pos)/2.f; float supHeight = (supPos-pos).length(); osg::Vec3 d = pos-supPos; d.normalize(); osg::Quat r; r.makeRotate(osg::Vec3(0.f,0.f,1.f),d); osg::Cylinder* cylinder = new osg::Cylinder(supCenter,10.f,supHeight); cylinder->setRotation(r); osg::ShapeDrawable* cylinderDrawable = new osg::ShapeDrawable(cylinder,hints.get()); osg::StateSet* ss = cylinderDrawable->getOrCreateStateSet(); ss->merge(*sset); supGeode->addDrawable(cylinderDrawable); } _parse->getCurrTop()->addChild(supGeode.get()); } break; default: break; } } } } if (addTextGeodeIntoSceneGraph) { _parse->getCurrTop()->addChild(textGeode.get()); textGeode->addDrawable(text.get()); } return (void*)1; } //---------------------------------------------------------------------------- // // Geometry Reader Class // //---------------------------------------------------------------------------- // Apply transformation on geometry class TransformFunctor : public osg::Drawable::AttributeFunctor { public: osg::Matrix _m; osg::Matrix _im; TransformFunctor(const osg::Matrix& m) { _m = m; _im.invert(_m); } virtual ~TransformFunctor() {} virtual void apply(osg::Drawable::AttributeType type,unsigned int count,osg::Vec3* begin) { if (type == osg::Drawable::VERTICES) { osg::Vec3* end = begin+count; for (osg::Vec3* itr=begin;itr vertices = new osg::Vec3Array(numVert); geom.GetVertices((float *)&(vertices->front())); // Turn the trpgGeometry into something osg can understand osg::ref_ptr geometry; // Get texture coordinates ; int num_tex; geom.GetNumTexCoordSets(num_tex); std::vector< osg::ref_ptr > tex_coords(num_tex); for (int texno = 0; texno < num_tex; texno++) { const trpgTexData* td = geom.GetTexCoordSet(texno); if (td) { tex_coords[texno] = new osg::Vec2Array(numVert); const float* sourcePtr = &(td->floatData[0]); float* destinationPtr = (float*)&((*tex_coords[texno])[0]); for (int i=0 ;i < numVert; ++i) { *destinationPtr++ = *sourcePtr++; *destinationPtr++ = *sourcePtr++; } } } // The normals osg::ref_ptr normals; if (numNorm == numVert) { normals = new osg::Vec3Array(numVert); geom.GetNormals((float*)&(normals->front())); } // Set up the primitive type switch (primType) { case trpgGeometry::Triangles: { geometry = new osg::Geometry; geometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::TRIANGLES,0,numPrims*3)); } break; case trpgGeometry::Quads: { geometry = new osg::Geometry; geometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,numPrims*4)); } break; case trpgGeometry::TriStrips: { geometry = new osg::Geometry; osg::DrawArrayLengths* dal = new osg::DrawArrayLengths(osg::PrimitiveSet::TRIANGLE_STRIP,0,numPrims); geom.GetPrimLengths(reinterpret_cast(&(dal->front()))); geometry->addPrimitiveSet(dal); } break; case trpgGeometry::TriFans: { geometry = new osg::Geometry; osg::DrawArrayLengths* dal = new osg::DrawArrayLengths(osg::PrimitiveSet::TRIANGLE_FAN,0,numPrims); geom.GetPrimLengths(reinterpret_cast(&(dal->front()))); geometry->addPrimitiveSet(dal); // Need to flip the fans coords. int ind = 0; int i; for (i=0;igetCurrTop(); // Is this geode group GeodeGroup *geodeTop = dynamic_cast(top); if (geometry.valid() && top) { // added this set use display list off since terrapage will // be creating and deleting these geometry leaves on the fly // so we don't want to be creating short lived display lists either. geometry->setUseDisplayList(false); geometry->setVertexArray(vertices.get()); if (normals.valid()) { geometry->setNormalArray(normals.get()); geometry->setNormalBinding(osg::Geometry::BIND_PER_VERTEX); } bool local; int matId; int matNo; geom.GetNumMaterial(matNo); osg::ref_ptr sset = 0L; for(int n_mat = 0; n_mat < matNo ; ++n_mat) { osg::ref_ptr tmp_ss = 0L; geom.GetMaterial(n_mat,matId,local); if( local ) tmp_ss = (*_parse->getLocalMaterials())[matId]; else { _parse->loadMaterial(matId); tmp_ss = (*_parse->getMaterials())[matId]; } if((sset!=0L) && sset.valid()) { if(tmp_ss.valid()) { osg::StateAttribute* texenv0 = tmp_ss->getTextureAttribute(0,osg::StateAttribute::TEXENV); if(texenv0) sset->setTextureAttribute(n_mat,texenv0); osg::StateAttribute* tex0 = tmp_ss->getTextureAttribute(0,osg::StateAttribute::TEXTURE); if(tex0) sset->setTextureAttributeAndModes(n_mat,tex0,osg::StateAttribute::ON); } // sset->merge(*tmp_ss.get()); } else sset = tmp_ss; } if (!tex_coords.empty()) { for (int texno = 0; texno < num_tex; texno++) { geometry->setTexCoordArray( texno, tex_coords[texno].get()); } } if (_parse->underBillboardSubgraph()) { geometry->setStateSet(sset.get()); TXPParser::TXPBillboardInfo info; _parse->getLastBillboardInfo(info); osg::ref_ptr billboard = new osg::Billboard; billboard->setAxis(osg::Vec3(0.0f,0.0,1.0f) ); billboard->setNormal(osg::Vec3(0.0f,-1.0,0.0f)); geometry->setUseDisplayList(true); switch (info.mode) { case trpgBillboard::World: billboard->setMode(osg::Billboard::POINT_ROT_WORLD); break; case trpgBillboard::Eye: billboard->setMode(osg::Billboard::POINT_ROT_EYE); break; default: billboard->setMode(osg::Billboard::AXIAL_ROT); break; } switch (info.type) { case trpgBillboard::Individual: { // compute center of billboard geometry const osg::BoundingBox& bbox = geometry->getBound(); osg::Vec3 center ((bbox._min + bbox._max) * 0.5f); // make billboard geometry coordinates relative to computed center osg::Matrix matrix; matrix.makeTranslate(-center[0], -center[1], -center[2]); TransformFunctor tf(matrix); geometry->accept(tf); geometry->dirtyBound(); billboard->addDrawable(geometry.get()); billboard->setPosition(0, center); } break; case trpgBillboard::Group: { osg::Vec3 center(info.center.x, info.center.y, info.center.z); // make billboard geometry coordinates relative to specified center osg::Matrix matrix; matrix.makeTranslate(-center[0], -center[1], -center[2]); TransformFunctor tf(matrix); geometry->accept(tf); geometry->dirtyBound(); billboard->addDrawable(geometry.get()); billboard->setPosition(0, center); } break; default: billboard->addDrawable(geometry.get()); osg::notify(osg::WARN) << "TerraPage loader: fell through case: " << __FILE__ << " " << __LINE__ << ".\n"; break; } top->addChild(billboard.get()); } else #if 0 if (_parse->underLayerSubgraph()) { osg::Geode* layer = _parse->getLayerGeode(); if (layer->getNumDrawables()) { osg::StateSet* poStateSet = new osg::StateSet; osg::PolygonOffset* polyoffset = new osg::PolygonOffset; poStateSet->merge(*sset.get()); polyoffset->setFactor(-1.0f);//*layer->getNumDrawables()); polyoffset->setUnits(-20.0f);//*layer->getNumDrawables()); poStateSet->setAttributeAndModes(polyoffset,osg::StateAttribute::ON); geometry->setStateSet(poStateSet); } else { geometry->setStateSet(sset.get()); } layer->addDrawable(geometry.get()); } else #else { geometry->setStateSet(sset.get()); if (geodeTop) { geodeTop->getGeode()->addDrawable(geometry.get()); _parse->setCurrentNode(geodeTop->getGeode()); } else { osg::Geode* geode = new osg::Geode; geode->addDrawable(geometry.get()); _parse->setCurrentNode(geode); _parse->getCurrTop()->addChild(geode); } } #endif } else { osg::notify(osg::WARN)<<"Detected potential memory leak in TXPParerse.cpp"<GetImageSize(s); int32 depth; tex->GetImageDepth(depth); trpgTexture::ImageType type; tex->GetImageType(type); GLenum internalFormat = (GLenum)-1; GLenum pixelFormat = (GLenum)-1; GLenum dataType = GL_UNSIGNED_BYTE; check_format(type,depth,internalFormat , pixelFormat , dataType); if(pixelFormat!=(GLenum)-1) { osg_texture = new osg::Texture2D(); // make sure the Texture unref's the Image after apply, when it is no longer needed. osg_texture->setUnRefImageDataAfterApply(true); osg::Image* image = new osg::Image; char* data = 0L; bool bMipmap; tex->GetIsMipmap(bMipmap); int32 num_mipmaps = bMipmap ? tex->CalcNumMipmaps() : 1; // this is currently line 130 // osg::Image do their own mipmaps if(num_mipmaps <= 1) { int32 size = tex->CalcTotalSize(); data = new char [size]; image_helper.GetLocalGL(tex,data,size); image->setImage(s.x,s.y,1,internalFormat, pixelFormat, dataType, (unsigned char*)data,osg::Image::USE_NEW_DELETE); } else { int32 size = tex->CalcTotalSize(); trpgTexture* tmp_tex = const_cast(tex); data = new char [size]; image_helper.GetLocalGL(tex,data,size); // Load entire texture including mipmaps image->setImage(s.x,s.y,1,internalFormat, pixelFormat, dataType, (unsigned char*)data, osg::Image::USE_NEW_DELETE); // now set mipmap data (offsets into image raw data) osg::Image::MipmapDataType mipmaps; // number of offsets in osg is one less than num_mipmaps // because it's assumed that first offset iz 0 mipmaps.resize(num_mipmaps-1); for( int k = 1 ; k < num_mipmaps;k++ ) { mipmaps[k-1] = tmp_tex->MipLevelOffset(k); } image->setMipmapLevels(mipmaps); } osg_texture->setImage(image); } return osg_texture; } //---------------------------------------------------------------------------- // Get a locale texture via the image helper osg::Texture2D* txp::getTemplateTexture(trpgrImageHelper& image_helper, trpgLocalMaterial* locmat, const trpgTexture* tex, int index) { osg::Texture2D* osg_texture= 0L; trpg2iPoint s; tex->GetImageSize(s); int32 depth; tex->GetImageDepth(depth); trpgTexture::ImageType type; tex->GetImageType(type); GLenum internalFormat = (GLenum)-1; GLenum pixelFormat = (GLenum)-1; GLenum dataType = GL_UNSIGNED_BYTE; check_format(type,depth,internalFormat , pixelFormat , dataType); if(pixelFormat!=(GLenum)-1) { osg_texture = new osg::Texture2D(); // make sure the Texture unref's the Image after apply, when it is no longer needed. osg_texture->setUnRefImageDataAfterApply(true); osg::Image* image = new osg::Image; char* data = 0L; bool bMipmap; tex->GetIsMipmap(bMipmap); int32 num_mipmaps = bMipmap ? tex->CalcNumMipmaps() : 1; // this is currently line 130 // osg::Image do their own mipmaps if(num_mipmaps <= 1) { int32 size = tex->CalcTotalSize(); data = new char [size]; image_helper.GetNthImageForLocalMat(locmat,index, data,size); image->setImage(s.x,s.y,1,internalFormat, pixelFormat, dataType, (unsigned char*)data,osg::Image::USE_NEW_DELETE); } else { int32 size = tex->CalcTotalSize(); trpgTexture* tmp_tex = const_cast(tex); data = new char [size]; image_helper.GetNthImageForLocalMat(locmat,index, data,size); // Load entire texture including mipmaps image->setImage(s.x,s.y,1,internalFormat, pixelFormat, dataType, (unsigned char*)data, osg::Image::USE_NEW_DELETE); // now set mipmap data (offsets into image raw data) osg::Image::MipmapDataType mipmaps; // number of offsets in osg is one less than num_mipmaps // because it's assumed that first offset iz 0 mipmaps.resize(num_mipmaps-1); for( int k = 1 ; k < num_mipmaps;k++ ) { mipmaps[k-1] = tmp_tex->MipLevelOffset(k); } image->setMipmapLevels(mipmaps); } osg_texture->setImage(image); } return osg_texture; }