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 <algorithm>
00024
00025 #include <cstring>
00026
00027 #include <boost/bind.hpp>
00028
00029 #include <osg/Geode>
00030 #include <osg/MatrixTransform>
00031 #include <osgDB/WriteFile>
00032 #include <osgDB/Registry>
00033 #include <osg/Switch>
00034 #include <osgDB/FileNameUtils>
00035
00036 #include <simgear/compiler.h>
00037 #include <simgear/structure/exception.hxx>
00038 #include <simgear/props/props.hxx>
00039 #include <simgear/props/props_io.hxx>
00040 #include <simgear/props/condition.hxx>
00041 #include <simgear/scene/util/SGNodeMasks.hxx>
00042
00043 #include "modellib.hxx"
00044 #include "SGPagedLOD.hxx"
00045 #include "SGReaderWriterXML.hxx"
00046 #include "SGReaderWriterXMLOptions.hxx"
00047
00048 #include "animation.hxx"
00049 #include "particles.hxx"
00050 #include "model.hxx"
00051 #include "SGText.hxx"
00052 #include "SGMaterialAnimation.hxx"
00053
00054 using namespace std;
00055 using namespace simgear;
00056 using namespace osg;
00057
00058 static osg::Node *
00059 sgLoad3DModel_internal(const std::string& path,
00060 const osgDB::ReaderWriter::Options* options,
00061 SGPropertyNode *overlay = 0);
00062
00063
00064 SGReaderWriterXML::SGReaderWriterXML()
00065 {
00066 supportsExtension("xml", "SimGear xml database format");
00067 }
00068
00069 SGReaderWriterXML::~SGReaderWriterXML()
00070 {
00071 }
00072
00073 const char* SGReaderWriterXML::className() const
00074 {
00075 return "XML database reader";
00076 }
00077
00078 osgDB::ReaderWriter::ReadResult
00079 SGReaderWriterXML::readNode(const std::string& fileName,
00080 const osgDB::ReaderWriter::Options* options) const
00081 {
00082 osg::Node *result=0;
00083 try {
00084 result=sgLoad3DModel_internal(fileName, options);
00085 } catch (const sg_throwable &t) {
00086 SG_LOG(SG_INPUT, SG_ALERT, "Failed to load model: " << t.getFormattedMessage());
00087 result=new osg::Node;
00088 }
00089 if (result)
00090 return result;
00091 else
00092 return ReadResult::FILE_NOT_HANDLED;
00093 }
00094
00095 class SGSwitchUpdateCallback : public osg::NodeCallback
00096 {
00097 public:
00098 SGSwitchUpdateCallback(SGCondition* condition) :
00099 mCondition(condition) {}
00100 virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) {
00101 assert(dynamic_cast<osg::Switch*>(node));
00102 osg::Switch* s = static_cast<osg::Switch*>(node);
00103
00104 if (mCondition && mCondition->test()) {
00105 s->setAllChildrenOn();
00106
00107
00108
00109 traverse(node, nv);
00110 } else
00111 s->setAllChildrenOff();
00112 }
00113
00114 private:
00115 SGSharedPtr<SGCondition> mCondition;
00116 };
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128 namespace {
00129 class SGDatabaseReference : public osg::Observer
00130 {
00131 public:
00132 SGDatabaseReference(osg::Referenced* referenced) :
00133 mReferenced(referenced)
00134 { }
00135 virtual void objectDeleted(void*)
00136 {
00137 mReferenced = 0;
00138 }
00139 private:
00140 osg::ref_ptr<osg::Referenced> mReferenced;
00141 };
00142
00143 void makeEffectAnimations(PropertyList& animation_nodes,
00144 PropertyList& effect_nodes)
00145 {
00146 for (PropertyList::iterator itr = animation_nodes.begin();
00147 itr != animation_nodes.end();
00148 ++itr) {
00149 SGPropertyNode_ptr effectProp;
00150 SGPropertyNode* animProp = itr->ptr();
00151 SGPropertyNode* typeProp = animProp->getChild("type");
00152 if (!typeProp)
00153 continue;
00154 const char* typeString = typeProp->getStringValue();
00155 if (!strcmp(typeString, "material")) {
00156 effectProp
00157 = SGMaterialAnimation::makeEffectProperties(animProp);
00158 } else if (!strcmp(typeString, "shader")) {
00159
00160 SGPropertyNode* shaderProp = animProp->getChild("shader");
00161 if (!shaderProp || strcmp(shaderProp->getStringValue(), "chrome"))
00162 continue;
00163 *itr = 0;
00164 SGPropertyNode* textureProp = animProp->getChild("texture");
00165 if (!textureProp)
00166 continue;
00167 effectProp = new SGPropertyNode();
00168 makeChild(effectProp.ptr(), "inherits-from")
00169 ->setValue("Effects/chrome");
00170 SGPropertyNode* paramsProp = makeChild(effectProp.get(), "parameters");
00171 makeChild(paramsProp, "chrome-texture")
00172 ->setValue(textureProp->getStringValue());
00173 }
00174 if (effectProp.valid()) {
00175 PropertyList objectNameNodes = animProp->getChildren("object-name");
00176 for (PropertyList::iterator objItr = objectNameNodes.begin(),
00177 end = objectNameNodes.end();
00178 objItr != end;
00179 ++objItr)
00180 effectProp->addChild("object-name")
00181 ->setStringValue((*objItr)->getStringValue());
00182 effect_nodes.push_back(effectProp);
00183
00184 }
00185 }
00186 animation_nodes.erase(remove_if(animation_nodes.begin(),
00187 animation_nodes.end(),
00188 !boost::bind(&SGPropertyNode_ptr::valid,
00189 _1)),
00190 animation_nodes.end());
00191 }
00192 }
00193
00194 static osg::Node *
00195 sgLoad3DModel_internal(const string &path,
00196 const osgDB::ReaderWriter::Options* options_,
00197 SGPropertyNode *overlay)
00198 {
00199 const SGReaderWriterXMLOptions* xmlOptions;
00200 xmlOptions = dynamic_cast<const SGReaderWriterXMLOptions*>(options_);
00201
00202 SGSharedPtr<SGPropertyNode> prop_root;
00203 osg::Node *(*load_panel)(SGPropertyNode *)=0;
00204 osg::ref_ptr<SGModelData> data;
00205
00206 if (xmlOptions) {
00207 prop_root = xmlOptions->getPropRoot();
00208 load_panel = xmlOptions->getLoadPanel();
00209 data = xmlOptions->getModelData();
00210 }
00211 if (!prop_root) {
00212 prop_root = new SGPropertyNode;
00213 }
00214
00215 osgDB::FilePathList filePathList;
00216 filePathList = osgDB::Registry::instance()->getDataFilePathList();
00217 filePathList.push_front(std::string());
00218
00219 SGPath modelpath = osgDB::findFileInPath(path, filePathList);
00220 if (modelpath.str().empty()) {
00221 SG_LOG(SG_INPUT, SG_ALERT, "Failed to load file: \"" << path << "\"");
00222 return 0;
00223 }
00224 SGPath texturepath = modelpath;
00225
00226 osg::ref_ptr<osg::Node> model;
00227 osg::ref_ptr<osg::Group> group;
00228 SGPropertyNode_ptr props = new SGPropertyNode;
00229
00230
00231 if (modelpath.extension() == "xml") {
00232 try {
00233 readProperties(modelpath.str(), props);
00234 } catch (const sg_throwable &t) {
00235 SG_LOG(SG_INPUT, SG_ALERT, "Failed to load xml: "
00236 << t.getFormattedMessage());
00237 throw;
00238 }
00239 if (overlay)
00240 copyProperties(overlay, props);
00241
00242 if (props->hasValue("/path")) {
00243 modelpath = modelpath.dir();
00244 modelpath.append(props->getStringValue("/path"));
00245 if (props->hasValue("/texture-path")) {
00246 texturepath = texturepath.dir();
00247 texturepath.append(props->getStringValue("/texture-path"));
00248 }
00249 } else {
00250 model = new osg::Node;
00251 }
00252
00253 SGPropertyNode *mp = props->getNode("multiplay");
00254 if (mp && prop_root && prop_root->getParent())
00255 copyProperties(mp, prop_root);
00256 } else {
00257 SG_LOG(SG_INPUT, SG_DEBUG, "model without wrapper: "
00258 << modelpath.str());
00259 }
00260
00261 osg::ref_ptr<SGReaderWriterXMLOptions> options
00262 = new SGReaderWriterXMLOptions(*options_);
00263 options->setPropRoot(prop_root);
00264 options->setLoadPanel(load_panel);
00265
00266
00267
00268 if (!model) {
00269 if (!texturepath.extension().empty())
00270 texturepath = texturepath.dir();
00271
00272 options->setDatabasePath(texturepath.str());
00273 osgDB::ReaderWriter::ReadResult modelResult
00274 = osgDB::Registry::instance()->readNode(modelpath.str(),
00275 options.get());
00276 if (!modelResult.validNode())
00277 throw sg_io_exception("Failed to load 3D model",
00278 sg_location(modelpath.str()));
00279 model = copyModel(modelResult.getNode());
00280
00281
00282
00283
00284
00285
00286 SGDatabaseReference* databaseReference;
00287 databaseReference = new SGDatabaseReference(modelResult.getNode());
00288 model->addObserver(databaseReference);
00289
00290
00291 TextureUpdateVisitor liveryUpdate(options->getDatabasePathList());
00292 model->accept(liveryUpdate);
00293
00294
00295
00296 UserDataCopyVisitor userDataCopyVisitor;
00297 model->accept(userDataCopyVisitor);
00298 }
00299 model->setName(modelpath.str());
00300
00301 bool needTransform=false;
00302
00303 SGPropertyNode *offsets = props->getNode("offsets", false);
00304 if (offsets) {
00305 needTransform=true;
00306 osg::MatrixTransform *alignmainmodel = new osg::MatrixTransform;
00307 alignmainmodel->setDataVariance(osg::Object::STATIC);
00308 osg::Matrix res_matrix;
00309 res_matrix.makeRotate(
00310 offsets->getFloatValue("pitch-deg", 0.0)*SG_DEGREES_TO_RADIANS,
00311 osg::Vec3(0, 1, 0),
00312 offsets->getFloatValue("roll-deg", 0.0)*SG_DEGREES_TO_RADIANS,
00313 osg::Vec3(1, 0, 0),
00314 offsets->getFloatValue("heading-deg", 0.0)*SG_DEGREES_TO_RADIANS,
00315 osg::Vec3(0, 0, 1));
00316
00317 osg::Matrix tmat;
00318 tmat.makeTranslate(offsets->getFloatValue("x-m", 0.0),
00319 offsets->getFloatValue("y-m", 0.0),
00320 offsets->getFloatValue("z-m", 0.0));
00321 alignmainmodel->setMatrix(res_matrix*tmat);
00322 group = alignmainmodel;
00323 }
00324 if (!group) {
00325 group = new osg::Group;
00326 }
00327 group->addChild(model.get());
00328
00329
00330 vector<SGPropertyNode_ptr> model_nodes = props->getChildren("model");
00331 for (unsigned i = 0; i < model_nodes.size(); i++) {
00332 SGPropertyNode_ptr sub_props = model_nodes[i];
00333
00334 SGPath submodelpath;
00335 osg::ref_ptr<osg::Node> submodel;
00336 string submodelFileName = sub_props->getStringValue("path");
00337 if (submodelFileName.size() > 2
00338 && !submodelFileName.compare(0, 2, "./" )) {
00339 submodelpath = modelpath.dir();
00340 submodelpath.append( submodelFileName.substr( 2 ) );
00341 } else {
00342 submodelpath = submodelFileName;
00343 }
00344 osg::ref_ptr<SGReaderWriterXMLOptions> options;
00345 options = new SGReaderWriterXMLOptions(*options_);
00346 options->setPropRoot(prop_root);
00347 options->setLoadPanel(load_panel);
00348 try {
00349 submodel = sgLoad3DModel_internal(submodelpath.str(), options.get(),
00350 sub_props->getNode("overlay"));
00351 } catch (const sg_throwable &t) {
00352 SG_LOG(SG_INPUT, SG_ALERT, "Failed to load submodel: " << t.getFormattedMessage());
00353 throw;
00354 }
00355
00356 osg::ref_ptr<osg::Node> submodel_final = submodel;
00357 SGPropertyNode *offs = sub_props->getNode("offsets", false);
00358 if (offs) {
00359 osg::Matrix res_matrix;
00360 osg::ref_ptr<osg::MatrixTransform> align = new osg::MatrixTransform;
00361 align->setDataVariance(osg::Object::STATIC);
00362 res_matrix.makeIdentity();
00363 res_matrix.makeRotate(
00364 offs->getDoubleValue("pitch-deg", 0.0)*SG_DEGREES_TO_RADIANS,
00365 osg::Vec3(0, 1, 0),
00366 offs->getDoubleValue("roll-deg", 0.0)*SG_DEGREES_TO_RADIANS,
00367 osg::Vec3(1, 0, 0),
00368 offs->getDoubleValue("heading-deg", 0.0)*SG_DEGREES_TO_RADIANS,
00369 osg::Vec3(0, 0, 1));
00370
00371 osg::Matrix tmat;
00372 tmat.makeIdentity();
00373 tmat.makeTranslate(offs->getDoubleValue("x-m", 0),
00374 offs->getDoubleValue("y-m", 0),
00375 offs->getDoubleValue("z-m", 0));
00376 align->setMatrix(res_matrix*tmat);
00377 align->addChild(submodel.get());
00378 submodel_final = align;
00379 }
00380 submodel_final->setName(sub_props->getStringValue("name", ""));
00381
00382 SGPropertyNode *cond = sub_props->getNode("condition", false);
00383 if (cond) {
00384 osg::ref_ptr<osg::Switch> sw = new osg::Switch;
00385 sw->setUpdateCallback(new SGSwitchUpdateCallback(sgReadCondition(prop_root, cond)));
00386 group->addChild(sw.get());
00387 sw->addChild(submodel_final.get());
00388 sw->setName("submodel condition switch");
00389 } else {
00390 group->addChild(submodel_final.get());
00391 }
00392 }
00393
00394 if ( load_panel ) {
00395
00396 vector<SGPropertyNode_ptr> panel_nodes = props->getChildren("panel");
00397 for (unsigned i = 0; i < panel_nodes.size(); i++) {
00398 SG_LOG(SG_INPUT, SG_DEBUG, "Loading a panel");
00399 osg::ref_ptr<osg::Node> panel = load_panel(panel_nodes[i]);
00400 if (panel_nodes[i]->hasValue("name"))
00401 panel->setName(panel_nodes[i]->getStringValue("name"));
00402 group->addChild(panel.get());
00403 }
00404 }
00405
00406 std::vector<SGPropertyNode_ptr> particle_nodes;
00407 particle_nodes = props->getChildren("particlesystem");
00408 for (unsigned i = 0; i < particle_nodes.size(); ++i) {
00409 if (i==0) {
00410 if (!texturepath.extension().empty())
00411 texturepath = texturepath.dir();
00412
00413 options->setDatabasePath(texturepath.str());
00414 }
00415 group->addChild(Particles::appendParticles(particle_nodes[i],
00416 prop_root,
00417 options.get()));
00418 }
00419
00420 std::vector<SGPropertyNode_ptr> text_nodes;
00421 text_nodes = props->getChildren("text");
00422 for (unsigned i = 0; i < text_nodes.size(); ++i) {
00423 group->addChild(SGText::appendText(text_nodes[i],
00424 prop_root,
00425 options.get()));
00426 }
00427 PropertyList effect_nodes = props->getChildren("effect");
00428 PropertyList animation_nodes = props->getChildren("animation");
00429
00430 makeEffectAnimations(animation_nodes, effect_nodes);
00431 {
00432 ref_ptr<Node> modelWithEffects
00433 = instantiateEffects(group.get(), effect_nodes, options.get());
00434 group = static_cast<Group*>(modelWithEffects.get());
00435 }
00436 for (unsigned i = 0; i < animation_nodes.size(); ++i)
00438 SGAnimation::animate(group.get(), animation_nodes[i], prop_root,
00439 options.get());
00440
00441 if (!needTransform && group->getNumChildren() < 2) {
00442 model = group->getChild(0);
00443 group->removeChild(model.get());
00444 if (data.valid())
00445 data->modelLoaded(modelpath.str(), props, model.get());
00446 return model.release();
00447 }
00448 if (data.valid())
00449 data->modelLoaded(modelpath.str(), props, group.get());
00450 if (props->hasChild("debug-outfile")) {
00451 std::string outputfile = props->getStringValue("debug-outfile",
00452 "debug-model.osg");
00453 osgDB::writeNodeFile(*group, outputfile);
00454 }
00455
00456 return group.release();
00457 }
00458