X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=simgear%2Fscene%2Fmodel%2Fmodel.cxx;h=1ea486f0d13afc5b1dae4353c449539f77df3d85;hb=d04cf4d8978866eb80a1639b6d4ddfe387338c77;hp=f8740adc0e7767eeb6b378593b7249e491657e2e;hpb=d769a9936bbdc2a9eb2c3b70d0b33acf5cf42e46;p=simgear.git diff --git a/simgear/scene/model/model.cxx b/simgear/scene/model/model.cxx index f8740adc..1ea486f0 100644 --- a/simgear/scene/model/model.cxx +++ b/simgear/scene/model/model.cxx @@ -7,345 +7,330 @@ #include #endif -#include +#include -#include // for strcmp() +#include -#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include -#include -#include -#include #include -#include +#include #include #include +#include -#include "animation.hxx" +#include "SGReaderWriterXMLOptions.hxx" #include "model.hxx" -SG_USING_STD(vector); +using std::vector; +osg::Texture2D* +SGLoadTexture2D(bool staticTexture, const std::string& path, + const osgDB::ReaderWriter::Options* options, + bool wrapu, bool wrapv, int) +{ + osg::Image* image; + if (options) + image = osgDB::readImageFile(path, options); + else + image = osgDB::readImageFile(path); + osg::ref_ptr texture = new osg::Texture2D; + texture->setImage(image); + if (staticTexture) + texture->setDataVariance(osg::Object::STATIC); + if (wrapu) + texture->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT); + else + texture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP); + if (wrapv) + texture->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT); + else + texture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP); + + if (image) { + int s = image->s(); + int t = image->t(); + + if (s <= t && 32 <= s) { + SGSceneFeatures::instance()->setTextureCompression(texture.get()); + } else if (t < s && 32 <= t) { + SGSceneFeatures::instance()->setTextureCompression(texture.get()); + } + } - -//////////////////////////////////////////////////////////////////////// -// Global state -//////////////////////////////////////////////////////////////////////// -static bool -model_filter = true; + return texture.release(); +} - -//////////////////////////////////////////////////////////////////////// -// Static utility functions. -//////////////////////////////////////////////////////////////////////// +namespace simgear +{ +using namespace std; +using namespace osg; +using simgear::CopyOp; -static int -model_filter_callback (ssgEntity * entity, int mask) +Node* copyModel(Node* model) { - return model_filter ? 1 : 0; + const CopyOp::CopyFlags flags = (CopyOp::DEEP_COPY_ALL + & ~CopyOp::DEEP_COPY_TEXTURES + & ~CopyOp::DEEP_COPY_IMAGES + & ~CopyOp::DEEP_COPY_STATESETS + & ~CopyOp::DEEP_COPY_STATEATTRIBUTES + & ~CopyOp::DEEP_COPY_ARRAYS + & ~CopyOp::DEEP_COPY_PRIMITIVES + // This will preserve display lists ... + & ~CopyOp::DEEP_COPY_DRAWABLES + & ~CopyOp::DEEP_COPY_SHAPES); + return (CopyOp(flags))(model); } -/** - * Callback to update an animation. - */ -static int -animation_callback (ssgEntity * entity, int mask) +TextureUpdateVisitor::TextureUpdateVisitor(const osgDB::FilePathList& pathList) : + NodeAndDrawableVisitor(NodeVisitor::TRAVERSE_ALL_CHILDREN), + _pathList(pathList) { - return ((SGAnimation *)entity->getUserData())->update(); } -/** - * Callback to restore the state after an animation. - */ -static int -restore_callback (ssgEntity * entity, int mask) +void TextureUpdateVisitor::apply(Node& node) { - ((SGAnimation *)entity->getUserData())->restore(); - return 1; + StateSet* stateSet = cloneStateSet(node.getStateSet()); + if (stateSet) + node.setStateSet(stateSet); + traverse(node); } +void TextureUpdateVisitor::apply(Drawable& drawable) +{ + StateSet* stateSet = cloneStateSet(drawable.getStateSet()); + if (stateSet) + drawable.setStateSet(stateSet); +} -/** - * Locate a named SSG node in a branch. - */ -static ssgEntity * -find_named_node (ssgEntity * node, const char * name) +Texture2D* TextureUpdateVisitor::textureReplace(int unit, const StateAttribute* attr) { - char * node_name = node->getName(); - if (node_name != 0 && !strcmp(name, node_name)) - return node; - else if (node->isAKindOf(ssgTypeBranch())) { - int nKids = node->getNumKids(); - for (int i = 0; i < nKids; i++) { - ssgEntity * result = - find_named_node(((ssgBranch*)node)->getKid(i), name); - if (result != 0) - return result; + using namespace osgDB; + const Texture2D* texture = dynamic_cast(attr); + + if (!texture) + return 0; + + const Image* image = texture->getImage(); + const string* fullFilePath = 0; + if (image) { + // The currently loaded file name + fullFilePath = &image->getFileName(); + + } else { + fullFilePath = &texture->getName(); + } + // The short name + string fileName = getSimpleFileName(*fullFilePath); + if (fileName.empty()) + return 0; + // The name that should be found with the current database path + string fullLiveryFile = findFileInPath(fileName, _pathList); + // If it is empty or they are identical then there is nothing to do + if (fullLiveryFile.empty() || fullLiveryFile == *fullFilePath) + return 0; + Image* newImage = readImageFile(fullLiveryFile); + if (!newImage) + return 0; + CopyOp copyOp(CopyOp::DEEP_COPY_ALL & ~CopyOp::DEEP_COPY_IMAGES); + Texture2D* newTexture = static_cast(copyOp(texture)); + if (!newTexture) { + return 0; + } else { + newTexture->setImage(newImage); + return newTexture; } - } - return 0; } -/** - * Splice a branch in between all child nodes and their parents. - */ -static void -splice_branch (ssgBranch * branch, ssgEntity * child) +StateSet* TextureUpdateVisitor::cloneStateSet(const StateSet* stateSet) { - int nParents = child->getNumParents(); - branch->addKid(child); - for (int i = 0; i < nParents; i++) { - ssgBranch * parent = child->getParent(i); - parent->replaceKid(child, branch); - } + typedef std::pair Tex2D; + vector newTextures; + StateSet* result = 0; + + if (!stateSet) + return 0; + int numUnits = stateSet->getTextureAttributeList().size(); + if (numUnits > 0) { + for (int i = 0; i < numUnits; ++i) { + const StateAttribute* attr + = stateSet->getTextureAttribute(i, StateAttribute::TEXTURE); + Texture2D* newTexture = textureReplace(i, attr); + if (newTexture) + newTextures.push_back(Tex2D(i, newTexture)); + } + if (!newTextures.empty()) { + result = static_cast(stateSet->clone(CopyOp())); + for (vector::iterator i = newTextures.begin(); + i != newTextures.end(); + ++i) { + result->setTextureAttribute(i->first, i->second); + } + } + } + return result; } -/** - * Make an offset matrix from rotations and position offset. - */ -void -sgMakeOffsetsMatrix( sgMat4 * result, double h_rot, double p_rot, double r_rot, - double x_off, double y_off, double z_off ) +UserDataCopyVisitor::UserDataCopyVisitor() : + NodeVisitor(NodeVisitor::NODE_VISITOR, + NodeVisitor::TRAVERSE_ALL_CHILDREN) { - sgMat4 rot_matrix; - sgMat4 pos_matrix; - sgMakeRotMat4(rot_matrix, h_rot, p_rot, r_rot); - sgMakeTransMat4(pos_matrix, x_off, y_off, z_off); - sgMultMat4(*result, pos_matrix, rot_matrix); } - -void -sgMakeAnimation( ssgBranch * model, - const char * name, - vector &name_nodes, - SGPropertyNode *prop_root, - SGPropertyNode_ptr node, - double sim_time_sec ) +void UserDataCopyVisitor::apply(Node& node) { - SGAnimation * animation = 0; - const char * type = node->getStringValue("type", "none"); - if (!strcmp("none", type)) { - animation = new SGNullAnimation(node); - } else if (!strcmp("range", type)) { - animation = new SGRangeAnimation(prop_root, node); - } else if (!strcmp("billboard", type)) { - animation = new SGBillboardAnimation(node); - } else if (!strcmp("select", type)) { - animation = new SGSelectAnimation(prop_root, node); - } else if (!strcmp("spin", type)) { - animation = new SGSpinAnimation(prop_root, node, sim_time_sec ); - } else if (!strcmp("timed", type)) { - animation = new SGTimedAnimation(node); - } else if (!strcmp("rotate", type)) { - animation = new SGRotateAnimation(prop_root, node); - } else if (!strcmp("translate", type)) { - animation = new SGTranslateAnimation(prop_root, node); - } else if (!strcmp("scale", type)) { - animation = new SGScaleAnimation(prop_root, node); - } else if (!strcmp("texrotate", type)) { - animation = new SGTexRotateAnimation(prop_root, node); - } else if (!strcmp("textranslate", type)) { - animation = new SGTexTranslateAnimation(prop_root, node); - } else if (!strcmp("texmultiple", type)) { - animation = new SGTexMultipleAnimation(prop_root, node); - } else if (!strcmp("blend", type)) { - animation = new SGBlendAnimation(prop_root, node); - } else if (!strcmp("alpha-test", type)) { - animation = new SGAlphaTestAnimation(node); - } else if (!strcmp("flash", type)) { - animation = new SGFlashAnimation(node); - } else if (!strcmp("dist-scale", type)) { - animation = new SGDistScaleAnimation(node); - } else { - animation = new SGNullAnimation(node); - SG_LOG(SG_INPUT, SG_WARN, "Unknown animation type " << type); - } - - if (name != 0) - animation->setName((char *)name); - - ssgEntity * object; - if (name_nodes.size() > 0) { - object = find_named_node(model, name_nodes[0]->getStringValue()); - if (object == 0) { - SG_LOG(SG_INPUT, SG_ALERT, "Object " << name_nodes[0]->getStringValue() - << " not found"); - delete animation; - animation = 0; + ref_ptr userData; + userData = SGSceneUserData::getSceneUserData(&node); + if (userData.valid()) { + SGSceneUserData* newUserData = new SGSceneUserData(*userData); + newUserData->setVelocity(0); + node.setUserData(newUserData); } - } else { - object = model; - } - - if ( animation == 0 ) - return; - - ssgBranch * branch = animation->getBranch(); - splice_branch(branch, object); - - for (unsigned int i = 1; i < name_nodes.size(); i++) { - const char * name = name_nodes[i]->getStringValue(); - object = find_named_node(model, name); - if (object == 0) { - SG_LOG(SG_INPUT, SG_ALERT, "Object " << name << " not found"); - delete animation; - animation = 0; - } else { - ssgBranch * oldParent = object->getParent(0); - branch->addKid(object); - oldParent->removeKid(object); - } - } - - if ( animation != 0 ) { - animation->init(); - branch->setUserData(animation); - branch->setTravCallback(SSG_CALLBACK_PRETRAV, animation_callback); - branch->setTravCallback(SSG_CALLBACK_POSTTRAV, restore_callback); - } + node.traverse(*this); } - -static void makeDList( ssgBranch *b ) +namespace +{ +class MakeEffectVisitor : public SplicingVisitor { - int nb = b->getNumKids(); - for (int i = 0; igetKid(i); - if (e->isAKindOf(ssgTypeLeaf())) { - ((ssgLeaf*)e)->makeDList(); - } else if (e->isAKindOf(ssgTypeBranch())) { - makeDList( (ssgBranch*)e ); +public: + typedef std::map EffectMap; + using SplicingVisitor::apply; + MakeEffectVisitor(const SGReaderWriterXMLOptions* options = 0) + : _options(options) + { } - } + virtual void apply(osg::Group& node); + virtual void apply(osg::Geode& geode); + EffectMap& getEffectMap() { return _effectMap; } + const EffectMap& getEffectMap() const { return _effectMap; } + void setDefaultEffect(SGPropertyNode* effect) + { + _currentEffectParent = effect; + } + SGPropertyNode* getDefaultEffect() { return _currentEffectParent; } +protected: + EffectMap _effectMap; + SGPropertyNode_ptr _currentEffectParent; + osg::ref_ptr _options; +}; + +void MakeEffectVisitor::apply(osg::Group& node) +{ + SGPropertyNode_ptr savedEffectRoot; + const string& nodeName = node.getName(); + bool restoreEffect = false; + if (!nodeName.empty()) { + EffectMap::iterator eitr = _effectMap.find(nodeName); + if (eitr != _effectMap.end()) { + savedEffectRoot = _currentEffectParent; + _currentEffectParent = eitr->second; + restoreEffect = true; + } + } + SplicingVisitor::apply(node); + // If a new node was created, copy the user data too. + ref_ptr userData = SGSceneUserData::getSceneUserData(&node); + if (userData.valid() && _childStack.back().back().get() != &node) + _childStack.back().back()->setUserData(new SGSceneUserData(*userData)); + if (restoreEffect) + _currentEffectParent = savedEffectRoot; } - - -//////////////////////////////////////////////////////////////////////// -// Global functions. -//////////////////////////////////////////////////////////////////////// - -ssgBranch * -sgLoad3DModel( const string &fg_root, const string &path, - SGPropertyNode *prop_root, - double sim_time_sec, ssgEntity *(*load_panel)(SGPropertyNode *) ) +void MakeEffectVisitor::apply(osg::Geode& geode) { - ssgBranch * model = 0; - SGPropertyNode props; - - // Load the 3D aircraft object itself - SGPath modelpath = path, texturepath = path; - if ( !ulIsAbsolutePathName( path.c_str() ) ) { - SGPath tmp = fg_root; - tmp.append(modelpath.str()); - modelpath = texturepath = tmp; - } - - // Check for an XML wrapper - if (modelpath.str().substr(modelpath.str().size() - 4, 4) == ".xml") { - readProperties(modelpath.str(), &props); - if (props.hasValue("/path")) { - modelpath = modelpath.dir(); - modelpath.append(props.getStringValue("/path")); - if (props.hasValue("/texture-path")) { - texturepath = texturepath.dir(); - texturepath.append(props.getStringValue("/texture-path")); - } + if (pushNode(getNewNode(geode))) + return; + osg::StateSet* ss = geode.getStateSet(); + if (!ss) { + pushNode(&geode); + return; + } + SGPropertyNode_ptr ssRoot = new SGPropertyNode; + makeParametersFromStateSet(ssRoot, ss); + SGPropertyNode_ptr effectRoot = new SGPropertyNode; + effect::mergePropertyTrees(effectRoot, ssRoot, _currentEffectParent); + Effect* effect = makeEffect(effectRoot, true, _options); + EffectGeode* eg = dynamic_cast(&geode); + if (eg) { + eg->setEffect(effect); } else { - if (model == 0) - model = new ssgBranch; + eg = new EffectGeode; + eg->setEffect(effect); + ref_ptr userData = SGSceneUserData::getSceneUserData(&geode); + if (userData.valid()) + eg->setUserData(new SGSceneUserData(*userData)); + for (int i = 0; i < geode.getNumDrawables(); ++i) + eg->addDrawable(geode.getDrawable(i)); } - } + pushResultNode(&geode, eg); - // Assume that textures are in - // the same location as the XML file. - if (model == 0) { - if (texturepath.extension() != "") - texturepath = texturepath.dir(); +} - ssgTexturePath((char *)texturepath.c_str()); - model = (ssgBranch *)ssgLoad((char *)modelpath.c_str()); - if (model == 0) - throw sg_exception("Failed to load 3D model"); - } +} - // Set up the alignment node - ssgTransform * alignmainmodel = new ssgTransform; - if ( load_panel == 0 ) - alignmainmodel->setTravCallback( SSG_CALLBACK_PRETRAV, model_filter_callback ); - alignmainmodel->addKid(model); - sgMat4 res_matrix; - sgMakeOffsetsMatrix(&res_matrix, - props.getFloatValue("/offsets/heading-deg", 0.0), - props.getFloatValue("/offsets/roll-deg", 0.0), - props.getFloatValue("/offsets/pitch-deg", 0.0), - props.getFloatValue("/offsets/x-m", 0.0), - props.getFloatValue("/offsets/y-m", 0.0), - props.getFloatValue("/offsets/z-m", 0.0)); - alignmainmodel->setTransform(res_matrix); - - unsigned int i; - - if ( load_panel ) { - // Load panels - vector panel_nodes = props.getChildren("panel"); - for (i = 0; i < panel_nodes.size(); i++) { - SG_LOG(SG_INPUT, SG_DEBUG, "Loading a panel"); - ssgEntity * panel = load_panel(panel_nodes[i]); - if (panel_nodes[i]->hasValue("name")) - panel->setName((char *)panel_nodes[i]->getStringValue("name")); - model->addKid(panel); +namespace +{ +class DefaultEffect : public simgear::Singleton +{ +public: + DefaultEffect() + { + _effect = new SGPropertyNode; + makeChild(_effect.ptr(), "inherits-from") + ->setStringValue("Effects/model-default"); } - } - - // Load sub-models - vector model_nodes = props.getChildren("model"); - for (i = 0; i < model_nodes.size(); i++) { - SGPropertyNode_ptr node = model_nodes[i]; - ssgTransform * align = new ssgTransform; - sgMat4 res_matrix; - sgMakeOffsetsMatrix(&res_matrix, - node->getFloatValue("offsets/heading-deg", 0.0), - node->getFloatValue("offsets/roll-deg", 0.0), - node->getFloatValue("offsets/pitch-deg", 0.0), - node->getFloatValue("offsets/x-m", 0.0), - node->getFloatValue("offsets/y-m", 0.0), - node->getFloatValue("offsets/z-m", 0.0)); - align->setTransform(res_matrix); - - ssgBranch * kid = sgLoad3DModel( fg_root, node->getStringValue("path"), - prop_root, sim_time_sec, load_panel ); - align->addKid(kid); - align->setName(node->getStringValue("name", "")); - model->addKid(align); - } - - // Load animations - vector animation_nodes = props.getChildren("animation"); - for (i = 0; i < animation_nodes.size(); i++) { - const char * name = animation_nodes[i]->getStringValue("name", 0); - vector name_nodes = - animation_nodes[i]->getChildren("object-name"); - sgMakeAnimation( model, name, name_nodes, prop_root, animation_nodes[i], - sim_time_sec); - } - - if ( model != 0 ) { - makeDList( model ); - } - - return alignmainmodel; + virtual ~DefaultEffect() {} + SGPropertyNode* getEffect() { return _effect.ptr(); } +protected: + SGPropertyNode_ptr _effect; +}; } -bool -sgSetModelFilter( bool filter ) +ref_ptr instantiateEffects(osg::Node* modelGroup, + PropertyList& effectProps, + const SGReaderWriterXMLOptions* options) { - bool old = model_filter; - model_filter = filter; - return old; + SGPropertyNode_ptr defaultEffectPropRoot; + MakeEffectVisitor visitor(options); + MakeEffectVisitor::EffectMap& emap = visitor.getEffectMap(); + for (PropertyList::iterator itr = effectProps.begin(), + end = effectProps.end(); + itr != end; + ++itr) + { + SGPropertyNode_ptr configNode = *itr; + std::vector objectNames = + configNode->getChildren("object-name"); + SGPropertyNode* defaultNode = configNode->getChild("default"); + if (defaultNode && defaultNode->getValue()) + defaultEffectPropRoot = configNode; + BOOST_FOREACH(SGPropertyNode_ptr objNameNode, objectNames) { + emap.insert(make_pair(objNameNode->getStringValue(), configNode)); + } + configNode->removeChild("default"); + configNode->removeChildren("object-name"); + } + if (!defaultEffectPropRoot) + defaultEffectPropRoot = DefaultEffect::instance()->getEffect(); + visitor.setDefaultEffect(defaultEffectPropRoot.ptr()); + modelGroup->accept(visitor); + osg::NodeList& result = visitor.getResults(); + return ref_ptr(result[0].get()); +} } - - // end of model.cxx