X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=simgear%2Fscene%2Fmodel%2FSGReaderWriterXML.cxx;h=1a83f2043aebf3edae8c68ab5899acc841a64186;hb=5a96b283f63cfacd3a3a90a82246defb038242d3;hp=2a4d612e6f2f485939dc79499b6a438993a430d4;hpb=6db9138eeb183d8ad00f0ccaf6a4e6ecb49e0197;p=simgear.git diff --git a/simgear/scene/model/SGReaderWriterXML.cxx b/simgear/scene/model/SGReaderWriterXML.cxx index 2a4d612e..1a83f204 100644 --- a/simgear/scene/model/SGReaderWriterXML.cxx +++ b/simgear/scene/model/SGReaderWriterXML.cxx @@ -20,7 +20,16 @@ # include #endif +#include +//yuck +#include +#include + +#include + +#include #include +#include #include #include #include @@ -32,22 +41,24 @@ #include #include #include +#include #include "modellib.hxx" -#include "SGPagedLOD.hxx" #include "SGReaderWriterXML.hxx" -#include "SGReaderWriterXMLOptions.hxx" #include "animation.hxx" #include "particles.hxx" #include "model.hxx" #include "SGText.hxx" +#include "SGMaterialAnimation.hxx" +using namespace std; using namespace simgear; +using namespace osg; static osg::Node * -sgLoad3DModel_internal(const std::string& path, - const osgDB::ReaderWriter::Options* options, +sgLoad3DModel_internal(const SGPath& path, + const osgDB::Options* options, SGPropertyNode *overlay = 0); @@ -67,13 +78,19 @@ const char* SGReaderWriterXML::className() const osgDB::ReaderWriter::ReadResult SGReaderWriterXML::readNode(const std::string& fileName, - const osgDB::ReaderWriter::Options* options) const + const osgDB::Options* options) const { osg::Node *result=0; try { - result=sgLoad3DModel_internal(fileName, options); - } catch (const sg_throwable &t) { - SG_LOG(SG_INPUT, SG_ALERT, "Failed to load model: " << t.getFormattedMessage()); + SGPath p = SGModelLib::findDataFile(fileName); + if (!p.exists()) { + return ReadResult::FILE_NOT_FOUND; + } + + result=sgLoad3DModel_internal(p, options); + } catch (const sg_exception &t) { + SG_LOG(SG_INPUT, SG_ALERT, "Failed to load model: " << t.getFormattedMessage() + << "\n\tfrom:" << fileName); result=new osg::Node; } if (result) @@ -129,40 +146,80 @@ public: private: osg::ref_ptr mReferenced; }; -} -static osg::Node * -sgLoad3DModel_internal(const string &path, - const osgDB::ReaderWriter::Options* options_, - SGPropertyNode *overlay) +void makeEffectAnimations(PropertyList& animation_nodes, + PropertyList& effect_nodes) { - const SGReaderWriterXMLOptions* xmlOptions; - xmlOptions = dynamic_cast(options_); - - SGSharedPtr prop_root; - osg::Node *(*load_panel)(SGPropertyNode *)=0; - osg::ref_ptr data; + for (PropertyList::iterator itr = animation_nodes.begin(); + itr != animation_nodes.end(); + ++itr) { + SGPropertyNode_ptr effectProp; + SGPropertyNode* animProp = itr->ptr(); + SGPropertyNode* typeProp = animProp->getChild("type"); + if (!typeProp) + continue; + const char* typeString = typeProp->getStringValue(); + if (!strcmp(typeString, "material")) { + effectProp + = SGMaterialAnimation::makeEffectProperties(animProp); + } else if (!strcmp(typeString, "shader")) { + + SGPropertyNode* shaderProp = animProp->getChild("shader"); + if (!shaderProp || strcmp(shaderProp->getStringValue(), "chrome")) + continue; + *itr = 0; // effect replaces animation + SGPropertyNode* textureProp = animProp->getChild("texture"); + if (!textureProp) + continue; + effectProp = new SGPropertyNode(); + makeChild(effectProp.ptr(), "inherits-from") + ->setValue("Effects/chrome"); + SGPropertyNode* paramsProp = makeChild(effectProp.get(), "parameters"); + makeChild(paramsProp, "chrome-texture") + ->setValue(textureProp->getStringValue()); + } + if (effectProp.valid()) { + PropertyList objectNameNodes = animProp->getChildren("object-name"); + for (PropertyList::iterator objItr = objectNameNodes.begin(), + end = objectNameNodes.end(); + objItr != end; + ++objItr) + effectProp->addChild("object-name") + ->setStringValue((*objItr)->getStringValue()); + effect_nodes.push_back(effectProp); - if (xmlOptions) { - prop_root = xmlOptions->getPropRoot(); - load_panel = xmlOptions->getLoadPanel(); - data = xmlOptions->getModelData(); - } - if (!prop_root) { - prop_root = new SGPropertyNode; + } } + animation_nodes.erase(remove_if(animation_nodes.begin(), + animation_nodes.end(), + !boost::bind(&SGPropertyNode_ptr::valid, + _1)), + animation_nodes.end()); +} +} - osgDB::FilePathList filePathList; - filePathList = osgDB::Registry::instance()->getDataFilePathList(); - filePathList.push_front(std::string()); - - SGPath modelpath = osgDB::findFileInPath(path, filePathList); - if (modelpath.str().empty()) { - SG_LOG(SG_INPUT, SG_ALERT, "Failed to load file: \"" << path << "\""); - return 0; +static osg::Node * +sgLoad3DModel_internal(const SGPath& path, + const osgDB::Options* dbOptions, + SGPropertyNode *overlay) +{ + if (!path.exists()) { + SG_LOG(SG_INPUT, SG_ALERT, "Failed to load file: \"" << path.str() << "\""); + return NULL; } - SGPath texturepath = modelpath; + osg::ref_ptr options; + options = SGReaderWriterOptions::copyOrCreate(dbOptions); + + SGPath modelpath(path); + SGPath texturepath(path); + SGPath modelDir(modelpath.dir()); + + SGSharedPtr prop_root = options->getPropertyNode(); + if (!prop_root.valid()) + prop_root = new SGPropertyNode; + osg::ref_ptr data = options->getModelData(); + osg::ref_ptr model; osg::ref_ptr group; SGPropertyNode_ptr props = new SGPropertyNode; @@ -171,7 +228,7 @@ sgLoad3DModel_internal(const string &path, if (modelpath.extension() == "xml") { try { readProperties(modelpath.str(), props); - } catch (const sg_throwable &t) { + } catch (const sg_exception &t) { SG_LOG(SG_INPUT, SG_ALERT, "Failed to load xml: " << t.getFormattedMessage()); throw; @@ -180,11 +237,18 @@ sgLoad3DModel_internal(const string &path, copyProperties(overlay, props); if (props->hasValue("/path")) { - modelpath = modelpath.dir(); - modelpath.append(props->getStringValue("/path")); + string modelPathStr = props->getStringValue("/path"); + modelpath = SGModelLib::findDataFile(modelPathStr, NULL, modelDir); + if (modelpath.isNull()) + throw sg_io_exception("Model file not found: '" + modelPathStr + "'", + path.str()); + if (props->hasValue("/texture-path")) { - texturepath = texturepath.dir(); - texturepath.append(props->getStringValue("/texture-path")); + string texturePathStr = props->getStringValue("/texture-path"); + texturepath = SGModelLib::findDataFile(texturePathStr, NULL, modelDir); + if (texturepath.isNull()) + throw sg_io_exception("Texture file not found: '" + texturePathStr + "'", + path.str()); } } else { model = new osg::Node; @@ -194,15 +258,11 @@ sgLoad3DModel_internal(const string &path, if (mp && prop_root && prop_root->getParent()) copyProperties(mp, prop_root); } else { - SG_LOG(SG_INPUT, SG_DEBUG, "model without wrapper: " - << modelpath.str()); + // model without wrapper } - osg::ref_ptr options - = new SGReaderWriterXMLOptions(*options_); - options->setPropRoot(prop_root); - options->setLoadPanel(load_panel); - + options->setPropertyNode(prop_root); + // Assume that textures are in // the same location as the XML file. if (!model) { @@ -210,13 +270,12 @@ sgLoad3DModel_internal(const string &path, texturepath = texturepath.dir(); options->setDatabasePath(texturepath.str()); - osg::Node* origModel - = osgDB::readNodeFile(modelpath.str(), options.get()); - - if (!origModel) - throw sg_io_exception("Failed to load 3D model", - sg_location(modelpath.str())); - model = copyModel(origModel); + osgDB::ReaderWriter::ReadResult modelResult; + modelResult = osgDB::readNodeFile(modelpath.str(), options.get()); + if (!modelResult.validNode()) + throw sg_io_exception("Failed to load 3D model:" + modelResult.message(), + modelpath.str()); + model = copyModel(modelResult.getNode()); // Add an extra reference to the model stored in the database. // That is to avoid expiring the object from the cache even if // it is still in use. Note that the object cache will think @@ -224,7 +283,7 @@ sgLoad3DModel_internal(const string &path, // clone all structural nodes here we need that extra // reference to the original object SGDatabaseReference* databaseReference; - databaseReference = new SGDatabaseReference(origModel); + databaseReference = new SGDatabaseReference(modelResult.getNode()); model->addObserver(databaseReference); // Update liveries @@ -273,26 +332,26 @@ sgLoad3DModel_internal(const string &path, SGPath submodelpath; osg::ref_ptr submodel; - string submodelFileName = sub_props->getStringValue("path"); - if ( submodelFileName.size() > 2 && submodelFileName.substr( 0, 2 ) == "./" ) { - submodelpath = modelpath.dir(); - submodelpath.append( submodelFileName.substr( 2 ) ); - } else { - submodelpath = submodelFileName; + + string subPathStr = sub_props->getStringValue("path"); + SGPath submodelPath = SGModelLib::findDataFile(subPathStr, + NULL, modelDir); + + if (submodelPath.isNull()) { + SG_LOG(SG_INPUT, SG_ALERT, "Failed to load file: \"" << subPathStr << "\""); + continue; } - osg::ref_ptr options; - options = new SGReaderWriterXMLOptions(*options_); - options->setPropRoot(prop_root); - options->setLoadPanel(load_panel); + try { - submodel = sgLoad3DModel_internal(submodelpath.str(), options.get(), + submodel = sgLoad3DModel_internal(submodelPath, options.get(), sub_props->getNode("overlay")); - } catch (const sg_throwable &t) { - SG_LOG(SG_INPUT, SG_ALERT, "Failed to load submodel: " << t.getFormattedMessage()); - throw; + } catch (const sg_exception &t) { + SG_LOG(SG_INPUT, SG_ALERT, "Failed to load submodel: " << t.getFormattedMessage() + << "\n\tfrom:" << t.getOrigin()); + continue; } - osg::ref_ptr submodel_final=submodel.get(); + osg::ref_ptr submodel_final = submodel; SGPropertyNode *offs = sub_props->getNode("offsets", false); if (offs) { osg::Matrix res_matrix; @@ -314,7 +373,7 @@ sgLoad3DModel_internal(const string &path, offs->getDoubleValue("z-m", 0)); align->setMatrix(res_matrix*tmat); align->addChild(submodel.get()); - submodel_final=align.get(); + submodel_final = align; } submodel_final->setName(sub_props->getStringValue("name", "")); @@ -330,6 +389,7 @@ sgLoad3DModel_internal(const string &path, } } // end of submodel loading + osg::Node *(*load_panel)(SGPropertyNode *) = options->getLoadPanel(); if ( load_panel ) { // Load panels vector panel_nodes = props->getChildren("panel"); @@ -345,15 +405,17 @@ sgLoad3DModel_internal(const string &path, std::vector particle_nodes; particle_nodes = props->getChildren("particlesystem"); for (unsigned i = 0; i < particle_nodes.size(); ++i) { + osg::ref_ptr options2; + options2 = new SGReaderWriterOptions(*options); if (i==0) { if (!texturepath.extension().empty()) texturepath = texturepath.dir(); - options->setDatabasePath(texturepath.str()); + options2->setDatabasePath(texturepath.str()); } group->addChild(Particles::appendParticles(particle_nodes[i], prop_root, - options.get())); + options2.get())); } std::vector text_nodes; @@ -363,9 +425,16 @@ sgLoad3DModel_internal(const string &path, prop_root, options.get())); } - - std::vector animation_nodes; - animation_nodes = props->getChildren("animation"); + PropertyList effect_nodes = props->getChildren("effect"); + PropertyList animation_nodes = props->getChildren("animation"); + PropertyList light_nodes = props->getChildren("light"); + // Some material animations (eventually all) are actually effects. + makeEffectAnimations(animation_nodes, effect_nodes); + { + ref_ptr modelWithEffects + = instantiateEffects(group.get(), effect_nodes, options.get()); + group = static_cast(modelWithEffects.get()); + } for (unsigned i = 0; i < animation_nodes.size(); ++i) /// OSGFIXME: duh, why not only model????? SGAnimation::animate(group.get(), animation_nodes[i], prop_root,