00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #ifdef HAVE_CONFIG_H
00020 # include <simgear_config.h>
00021 #endif
00022
00023 #include "SGText.hxx"
00024
00025 #include <simgear/math/SGMath.hxx>
00026 #include <simgear/misc/sg_path.hxx>
00027
00028 #include <osg/Geode>
00029 #include <osg/MatrixTransform>
00030 #include <osgText/Text>
00031 #include <osgText/Font>
00032
00033 class SGText::UpdateCallback : public osg::NodeCallback {
00034 public:
00035 UpdateCallback( osgText::Text * aText, SGConstPropertyNode_ptr aProperty, double aScale, double aOffset, double aTruncate, double aNumeric, const char * aFormat ) :
00036 text( aText ),
00037 property( aProperty ),
00038 scale( aScale ),
00039 offset( aOffset ),
00040 truncate( aTruncate ),
00041 numeric( aNumeric ),
00042 format( aFormat )
00043 {
00044 if( format.size() == 0 ) {
00045 if( numeric ) format = "%f";
00046 else format = "%s";
00047 }
00048 }
00049
00050 private:
00051 virtual void operator()(osg::Node * node, osg::NodeVisitor *nv );
00052 osgText::Text * text;
00053 SGConstPropertyNode_ptr property;
00054 double scale;
00055 double offset;
00056 bool truncate;
00057 bool numeric;
00058 string format;
00059 };
00060
00061 void SGText::UpdateCallback::operator()(osg::Node * node, osg::NodeVisitor *nv )
00062 {
00063
00064
00065
00066 char buf[256];
00067 if( numeric ) {
00068 double d = property->getDoubleValue() * scale + offset;
00069 if (truncate) d = (d < 0) ? -floor(-d) : floor(d);
00070 snprintf( buf, sizeof(buf)-1, format.c_str(), d );
00071 } else {
00072 snprintf( buf, sizeof(buf)-1, format.c_str(), property->getStringValue() );
00073 }
00074 if( text->getText().createUTF8EncodedString().compare( buf ) ) {
00075
00076
00077
00078 text->setText( buf );
00079 text->update();
00080 }
00081 traverse( node, nv );
00082 }
00083
00084 osg::Node * SGText::appendText(const SGPropertyNode* configNode,
00085 SGPropertyNode* modelRoot, const osgDB::ReaderWriter::Options* options)
00086 {
00087 SGConstPropertyNode_ptr p;
00088
00089 SG_LOG(SG_GENERAL, SG_DEBUG, "Creating a text object");
00090
00091 osgText::Text * text = new osgText::Text();
00092 osg::Geode * g = new osg::Geode;
00093 g->addDrawable( text );
00094
00095 SGPath path("Fonts" );
00096 path.append( configNode->getStringValue( "font", "Helvetica" ));
00097 text->setFont( path.str() );
00098
00099 text->setCharacterSize(configNode->getDoubleValue("character-size", 1.0 ),
00100 configNode->getDoubleValue("character-aspect-ratio", 1.0 ));
00101
00102 if( (p = configNode->getNode( "font-resolution" )) != NULL )
00103 text->setFontResolution( p->getIntValue( "width", 32 ), p->getIntValue( "height", 32 ) );
00104
00105 if( (p = configNode->getNode( "kerning" )) != NULL ) {
00106 string kerning = p->getStringValue();
00107 if( kerning.compare( "default" ) == 0 ) {
00108 text->setKerningType( osgText::KERNING_DEFAULT );
00109 } else if( kerning.compare( "unfitted" ) == 0 ) {
00110 text->setKerningType( osgText::KERNING_UNFITTED );
00111 } else if( kerning.compare( "none" ) == 0 ) {
00112 text->setKerningType( osgText::KERNING_NONE );
00113 } else {
00114 SG_LOG(SG_GENERAL, SG_ALERT, "ignoring unknown kerning'" << kerning << "'." );
00115 }
00116 }
00117
00118 if( ( p = configNode->getNode( "axis-alignment" )) != NULL ) {
00119 string axisAlignment = p->getStringValue();
00120 if( axisAlignment.compare( "xy-plane" ) == 0 ) {
00121 text->setAxisAlignment( osgText::Text::XY_PLANE );
00122 } else if( axisAlignment.compare( "reversed-xy-plane" ) == 0 ) {
00123 text->setAxisAlignment( osgText::Text::REVERSED_XY_PLANE );
00124 } else if( axisAlignment.compare( "xz-plane" ) == 0 ) {
00125 text->setAxisAlignment( osgText::Text::XZ_PLANE );
00126 } else if( axisAlignment.compare( "reversed-xz-plane" ) == 0 ) {
00127 text->setAxisAlignment( osgText::Text::REVERSED_XZ_PLANE );
00128 } else if( axisAlignment.compare( "yz-plane" ) == 0 ) {
00129 text->setAxisAlignment( osgText::Text::YZ_PLANE );
00130 } else if( axisAlignment.compare( "reversed-yz-plane" ) == 0 ) {
00131 text->setAxisAlignment( osgText::Text::REVERSED_YZ_PLANE );
00132 } else if( axisAlignment.compare( "screen" ) == 0 ) {
00133 text->setAxisAlignment( osgText::Text::SCREEN );
00134 } else {
00135 SG_LOG(SG_GENERAL, SG_ALERT, "ignoring unknown axis-alignment'" << axisAlignment << "'." );
00136 }
00137 }
00138
00139 unsigned drawMode = osgText::Text::TEXT;
00140 if( (p = configNode->getNode( "draw-text" )) != NULL && p->getBoolValue() == false )
00141 drawMode &= ~ osgText::Text::TEXT;
00142
00143 if( (p = configNode->getNode( "draw-alignment" )) != NULL && p->getBoolValue() == true )
00144 drawMode |= osgText::Text::ALIGNMENT;
00145
00146 if( (p = configNode->getNode( "draw-boundingbox" )) != NULL && p->getBoolValue() == true )
00147 drawMode |= osgText::Text::BOUNDINGBOX;
00148
00149 text->setDrawMode( drawMode );
00150
00151 if( (p = configNode->getNode( "alignment" )) != NULL ) {
00152 string alignment = p->getStringValue();
00153 if( alignment.compare( "left-top" ) == 0 ) {
00154 text->setAlignment( osgText::Text::LEFT_TOP );
00155 } else if( alignment.compare( "left-center" ) == 0 ) {
00156 text->setAlignment( osgText::Text::LEFT_CENTER );
00157 } else if( alignment.compare( "left-bottom" ) == 0 ) {
00158 text->setAlignment( osgText::Text::LEFT_BOTTOM );
00159 } else if( alignment.compare( "center-top" ) == 0 ) {
00160 text->setAlignment( osgText::Text::CENTER_TOP );
00161 } else if( alignment.compare( "center-center" ) == 0 ) {
00162 text->setAlignment( osgText::Text::CENTER_CENTER );
00163 } else if( alignment.compare( "center-bottom" ) == 0 ) {
00164 text->setAlignment( osgText::Text::CENTER_BOTTOM );
00165 } else if( alignment.compare( "right-top" ) == 0 ) {
00166 text->setAlignment( osgText::Text::RIGHT_TOP );
00167 } else if( alignment.compare( "right-center" ) == 0 ) {
00168 text->setAlignment( osgText::Text::RIGHT_CENTER );
00169 } else if( alignment.compare( "right-bottom" ) == 0 ) {
00170 text->setAlignment( osgText::Text::RIGHT_BOTTOM );
00171 } else if( alignment.compare( "left-baseline" ) == 0 ) {
00172 text->setAlignment( osgText::Text::LEFT_BASE_LINE );
00173 } else if( alignment.compare( "center-baseline" ) == 0 ) {
00174 text->setAlignment( osgText::Text::CENTER_BASE_LINE );
00175 } else if( alignment.compare( "right-baseline" ) == 0 ) {
00176 text->setAlignment( osgText::Text::RIGHT_BASE_LINE );
00177 } else if( alignment.compare( "baseline" ) == 0 ) {
00178 text->setAlignment( osgText::Text::BASE_LINE );
00179 } else {
00180 SG_LOG(SG_GENERAL, SG_ALERT, "ignoring unknown text-alignment '" << alignment <<"'." );
00181 }
00182 }
00183
00184 if( (p = configNode->getNode( "layout" )) != NULL ) {
00185 string layout = p->getStringValue();
00186 if( layout.compare( "left-to-right" ) == 0 ) {
00187 text->setLayout( osgText::Text::LEFT_TO_RIGHT );
00188 } else if( layout.compare( "right-to-left" ) == 0 ) {
00189 text->setLayout( osgText::Text::RIGHT_TO_LEFT );
00190 } else if( layout.compare( "vertical" ) == 0 ) {
00191 text->setLayout( osgText::Text::VERTICAL );
00192 } else {
00193 SG_LOG(SG_GENERAL, SG_ALERT, "ignoring unknown layout '" << layout <<"'." );
00194 }
00195 }
00196
00197 if( (p = configNode->getNode( "max-width" )) != NULL )
00198 text->setMaximumWidth( p->getDoubleValue() );
00199
00200 if( (p = configNode->getNode( "max-height" )) != NULL )
00201 text->setMaximumHeight( p->getDoubleValue() );
00202
00203
00204 string type = configNode->getStringValue( "type", "literal" );
00205 if( type == "literal" ) {
00206 text->setText( configNode->getStringValue( "text", "" ) );
00207 } else {
00208 SGConstPropertyNode_ptr property = modelRoot->getNode( configNode->getStringValue( "property", "foo" ), true );
00209 const char * format = configNode->getStringValue( "format", "" );
00210 double scale = configNode->getDoubleValue( "scale", 1.0 );
00211 double offset = configNode->getDoubleValue( "offset", 0.0 );
00212 bool truncate = configNode->getBoolValue( "truncate", false );
00213
00214 if( (p = configNode->getNode( "property")) != NULL ) {
00215 p = modelRoot->getNode( p->getStringValue(), true );
00216 UpdateCallback * uc = new UpdateCallback( text, property, scale, offset, truncate, type == "number-value", format );
00217 g->setUpdateCallback( uc );
00218 }
00219 }
00220
00221 osg::Node * reply = NULL;
00222 if( (p = configNode->getNode( "offsets")) == NULL ) {
00223 reply = g;
00224 } else {
00225
00226
00227 osg::MatrixTransform *align = new osg::MatrixTransform;
00228 osg::Matrix res_matrix;
00229 res_matrix.makeRotate(
00230 p->getFloatValue("pitch-deg", 0.0)*SG_DEGREES_TO_RADIANS,
00231 osg::Vec3(0, 1, 0),
00232 p->getFloatValue("roll-deg", 0.0)*SG_DEGREES_TO_RADIANS,
00233 osg::Vec3(1, 0, 0),
00234 p->getFloatValue("heading-deg", 0.0)*SG_DEGREES_TO_RADIANS,
00235 osg::Vec3(0, 0, 1));
00236
00237 osg::Matrix tmat;
00238 tmat.makeTranslate(configNode->getFloatValue("offsets/x-m", 0.0),
00239 configNode->getFloatValue("offsets/y-m", 0.0),
00240 configNode->getFloatValue("offsets/z-m", 0.0));
00241
00242 align->setMatrix(res_matrix * tmat);
00243 align->addChild( g );
00244 reply = align;
00245 }
00246
00247 if( (p = configNode->getNode( "name" )) != NULL )
00248 reply->setName(p->getStringValue());
00249 else
00250 reply->setName("text");
00251 return reply;
00252 }