diff --git a/src/osgPlugins/txp/ReaderWriterTXP.cpp b/src/osgPlugins/txp/ReaderWriterTXP.cpp index 60530c2ec..ebe3a65e4 100644 --- a/src/osgPlugins/txp/ReaderWriterTXP.cpp +++ b/src/osgPlugins/txp/ReaderWriterTXP.cpp @@ -88,7 +88,7 @@ osgDB::ReaderWriter::ReadResult ReaderWriterTXP::readNode(const std::string& fil pagedLOD->setRange(1,0,info.minRange); pagedLOD->setCenter(info.center); pagedLOD->setRadius(info.radius); - //pagedLOD->setPriorityOffset(0,numLods-lod); + pagedLOD->setPriorityOffset(0,numLods-lod); pagedLOD->setPriorityScale(0,1.0f); pagedLOD->setNumChildrenThatCannotBeExpired(1); pagedLOD->setTileId(x,y,lod); @@ -146,7 +146,7 @@ osgDB::ReaderWriter::ReadResult ReaderWriterTXP::readNode(const std::string& fil pagedLOD->setRange(1,0,info.minRange); pagedLOD->setCenter(info.center); pagedLOD->setRadius(info.radius); - //pagedLOD->setPriorityOffset(0,numLods-lod); + pagedLOD->setPriorityOffset(0,numLods-lod); pagedLOD->setPriorityScale(0,1.0f); pagedLOD->setNumChildrenThatCannotBeExpired(1); pagedLOD->setTileId(tileX,tileY,tileLOD); diff --git a/src/osgPlugins/txp/TXPArchive.cpp b/src/osgPlugins/txp/TXPArchive.cpp index 9cab78d2c..b0ac6b917 100644 --- a/src/osgPlugins/txp/TXPArchive.cpp +++ b/src/osgPlugins/txp/TXPArchive.cpp @@ -22,6 +22,8 @@ #include #include #include +#include + #include "TXPArchive.h" #include "TXPParser.h" @@ -518,26 +520,88 @@ bool TXPArchive::loadLightAttributes() return true; } +void trim(std::string& str) +{ + while (!str.empty() && isspace(str[str.length()-1])) + str.erase(str.length()-1); + while (!str.empty() && isspace(str[0])) + str.erase(0,1); +} bool TXPArchive::loadTextStyles() { - const trpgTextStyleTable *textStyleTable = GetTextStyleTable(); - if (!textStyleTable) return false; + const trpgTextStyleTable *textStyleTable = GetTextStyleTable(); + if (!textStyleTable) return false; + if (textStyleTable->GetNumStyle() < 1) return true; - _fonts.resize(textStyleTable->GetNumStyle()); - for (int i = 0; i < textStyleTable->GetNumStyle(); i++) - { - const trpgTextStyle *textStyle = textStyleTable->GetStyleRef(i); - if (!textStyle) continue; + // try fontmap.txt + std::map< std::string, std::string > fontmap; - const std::string *fontName = textStyle->GetFont(); - if (!fontName) continue; + std::string fmapfname = std::string(getDir())+"\\fontmap.txt"; + std::ifstream fmapfile; + fmapfile.open(fmapfname.c_str(),std::ios::in); - osg::ref_ptr< osgText::Font > font = osgText::readFontFile(*fontName + ".ttf"); + if (fmapfile.is_open()) + { + osg::notify(osg::NOTICE) << "txp:: Font map file found: " << fmapfname << std::endl; + std::string line; + while (getline(fmapfile,line)) + { + int ix = line.find_first_of('='); + if (ix != std::string::npos) + { + std::string fontname = line.substr(0,ix); + std::string fontfilename = line.substr(ix+1,line.length()-ix+1); - _fonts[i] = font; - } + trim(fontname); + trim(fontfilename); - return true; + fontmap[fontname] = fontfilename; + + } + } + fmapfile.close(); + } + else + { + osg::notify(osg::NOTICE) << "txp:: No font map file found: " << fmapfname << std::endl; + osg::notify(osg::NOTICE) << "txp:: All fonts defaulted to ARIAL.TTF" << std::endl; + } + + _fonts.resize(textStyleTable->GetNumStyle()); + _fcolors.resize(textStyleTable->GetNumStyle()); + for (int i = 0; i < textStyleTable->GetNumStyle(); i++) + { + const trpgTextStyle *textStyle = textStyleTable->GetStyleRef(i); + if (!textStyle) continue; + + const std::string *fontName = textStyle->GetFont(); + if (!fontName) continue; + + std::string fontfilename = fontmap[*fontName]; + if (!fontfilename.length()) fontfilename = "ARIAL.TTF"; + osg::ref_ptr< osgText::Font > font = osgText::readFontFile(fontfilename); + + _fonts[i] = font; + + const trpgMatTable* matTable = GetMaterialTable(); + if (matTable) + { + int matId = textStyle->GetMaterial(); + const trpgMaterial* mat = matTable->GetMaterialRef(0,matId); + if (mat) + { + trpgColor faceColor; + mat->GetColor(faceColor); + + float64 alpha; + mat->GetAlpha(alpha); + + _fcolors[i] = osg::Vec4(faceColor.red, faceColor.green, faceColor.blue, alpha ); + } + } + } + + return true; } void TXPArchive::addLightAttribute(osgSim::LightPointNode* lpn, osg::StateSet* fallback, const osg::Vec3& att) diff --git a/src/osgPlugins/txp/TXPArchive.h b/src/osgPlugins/txp/TXPArchive.h index f5769e252..1c0643916 100644 --- a/src/osgPlugins/txp/TXPArchive.h +++ b/src/osgPlugins/txp/TXPArchive.h @@ -84,6 +84,7 @@ public: // Load the text styles from the archive bool loadTextStyles(); inline std::vector< osg::ref_ptr >& getStyles() { return _fonts; } + inline std::vector< osg::Vec4 >& getTextColors() { return _fcolors; } // Add light attrib void addLightAttribute(osgSim::LightPointNode* lpn, osg::StateSet* fallback , const osg::Vec3& attitude); @@ -188,6 +189,9 @@ protected: // Text styles / Fonts std::vector< osg::ref_ptr > _fonts; + // Text colors + std::vector< osg::Vec4 > _fcolors; + // OpenThreads::Mutex _mutex; diff --git a/src/osgPlugins/txp/TXPParser.cpp b/src/osgPlugins/txp/TXPParser.cpp index 9023b0d5a..20658fd0f 100644 --- a/src/osgPlugins/txp/TXPParser.cpp +++ b/src/osgPlugins/txp/TXPParser.cpp @@ -24,6 +24,8 @@ #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"); TXPParser::TXPParser(): @@ -765,13 +767,35 @@ void* labelRead::Parse(trpgToken /*tok*/,trpgReadBuffer &buf) osg::Vec3 pos(label.GetLocation().x, label.GetLocation().y, label.GetLocation().z); osg::ref_ptr< osg::Geode > textGeode = new osg::Geode; - _parse->getCurrTop()->addChild(textGeode.get()); - osg::ref_ptr< osgText::Text > text = new osgText::Text; - textGeode->addDrawable(text.get()); // Text - text->setText(*labelText); + std::ostringstream os; + int 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 @@ -787,12 +811,13 @@ void* labelRead::Parse(trpgToken /*tok*/,trpgReadBuffer &buf) text->setAlignment(osgText::Text::CENTER_BOTTOM); } // Axis alignment - text->setAxisAlignment(osgText::Text::XY_PLANE); + 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(); @@ -802,34 +827,219 @@ void* labelRead::Parse(trpgToken /*tok*/,trpgReadBuffer &buf) if (!textStyle) return (void*)1; // Size - text->setCharacterSize(textStyle->GetCharacterSize()*label.GetScale()); + 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::SCREEN); + text->setAxisAlignment(osgText::Text::XY_PLANE); + text->setAutoRotateToScreen(true); break; case trpgLabelProperty::VertBillboard: - break; - case trpgLabelProperty::Panel: + 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->setPos(0,pos); + + _parse->getCurrTop()->addChild(billboard.get()); + } break; case trpgLabelProperty::Cube: - break; - case trpgLabelProperty::MaxLabelType: + 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; } - } -#if 1 - osg::TessellationHints* hints = new osg::TessellationHints; - hints->setDetailRatio(0.5f); - - textGeode->addDrawable(new osg::ShapeDrawable(new osg::Cone(pos,1.f,50.f),hints)); -#endif + 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; + } + + + } + } + } + if (addTextGeodeIntoSceneGraph) + { + _parse->getCurrTop()->addChild(textGeode.get()); + textGeode->addDrawable(text.get()); + } return (void*)1; } diff --git a/src/osgPlugins/txp/TXP_LABELS.README b/src/osgPlugins/txp/TXP_LABELS.README new file mode 100644 index 000000000..83d6f3f72 --- /dev/null +++ b/src/osgPlugins/txp/TXP_LABELS.README @@ -0,0 +1,17 @@ +Labels are objects that float above the terrain (usually) and display +some text message to the user. They're primarily used in 3D map sort of +application. In other words, they're not intended to be real world objects. +You would use one if you want to float a message such as "Natural History Museum" +over a specific building in a visual database. + +They point to a font name to be used for the text displayed. The txp loader will look +for fontmap.txt file in the txp archive directory in which font name to font file name +map should be provided since osg uses freetype for the Text displayed and there is no +interface to create fonts based on their name (or at least I was not able to find it :) .. ) + - it uses the font file name instead + +Ex: +Times New Roman = TIMES.TTF +Arial = ARIAL.TTF +Arial Narrow = ARIALN.TTF +Courier New = COUR.TTF \ No newline at end of file diff --git a/src/osgPlugins/txp/TileMapper.cpp b/src/osgPlugins/txp/TileMapper.cpp index cf1dc0e90..85270ebb3 100644 --- a/src/osgPlugins/txp/TileMapper.cpp +++ b/src/osgPlugins/txp/TileMapper.cpp @@ -224,9 +224,11 @@ bool TileMapper::canParentBeTraversed(const TileIdentifier& tid) const TileMap::const_iterator itr = _tileMap.find(tid); if (itr==_tileMap.end()) { +#if 0 // not found tile in _tileMap, what should we do?? // return true as a fallback right now. std::cout<<"TileMapper::canDescend() Not found tile in map"<