/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
*
* This library is open source and may be redistributed and/or modified under
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
* (at your option) any later version. The full license is in LICENSE file
* included with this distribution, and on the openscenegraph.org website.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* OpenSceneGraph Public License for more details.
*/ #include <osg/Node>
#include <osg/Group>
#include <osg/NodeVisitor>
#include <osg/Notify>
#include <osg/OccluderNode>
#include <osg/Transform>
#include <osg/UserDataContainer> #include <algorithm> using namespace osg; namespace osg
{
/// Helper class for generating NodePathList.
class CollectParentPaths : public NodeVisitor
{
public:
CollectParentPaths(const osg::Node* haltTraversalAtNode=) :
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_PARENTS),
_haltTraversalAtNode(haltTraversalAtNode)
{
setNodeMaskOverride(0xffffffff);
} virtual void apply(osg::Node& node)
{
if (node.getNumParents()== || &node==_haltTraversalAtNode)
{
_nodePaths.push_back(getNodePath());
}
else
{
traverse(node);
}
} const Node* _haltTraversalAtNode;
NodePath _nodePath;
NodePathList _nodePaths;
};
} Node::Node()
:Object(true)
{
_boundingSphereComputed = false;
_nodeMask = 0xffffffff; _numChildrenRequiringUpdateTraversal = ; _numChildrenRequiringEventTraversal = ; _cullingActive = true;
_numChildrenWithCullingDisabled = ; _numChildrenWithOccluderNodes = ;
} Node::Node(const Node& node,const CopyOp& copyop):
Object(node,copyop),
_initialBound(node._initialBound),
_boundingSphere(node._boundingSphere),
_boundingSphereComputed(node._boundingSphereComputed),
_parents(), // leave empty as parentList is managed by Group.
_updateCallback(copyop(node._updateCallback.get())),
_numChildrenRequiringUpdateTraversal(), // assume no children yet.
_numChildrenRequiringEventTraversal(), // assume no children yet.
_cullCallback(copyop(node._cullCallback.get())),
_cullingActive(node._cullingActive),
_numChildrenWithCullingDisabled(), // assume no children yet.
_numChildrenWithOccluderNodes(),
_nodeMask(node._nodeMask)
{
setStateSet(copyop(node._stateset.get()));
} Node::~Node()
{
// cleanly detach any associated stateset (include remove parent links)
setStateSet();
} void Node::addParent(osg::Group* parent)
{
OpenThreads::ScopedPointerLock<OpenThreads::Mutex> lock(getRefMutex()); _parents.push_back(parent);
} void Node::removeParent(osg::Group* parent)
{
OpenThreads::ScopedPointerLock<OpenThreads::Mutex> lock(getRefMutex()); ParentList::iterator pitr = std::find(_parents.begin(), _parents.end(), parent);
if (pitr!=_parents.end()) _parents.erase(pitr);
} void Node::accept(NodeVisitor& nv)
{
if (nv.validNodeMask(*this))
{
nv.pushOntoNodePath(this);
nv.apply(*this);
nv.popFromNodePath();
}
} void Node::ascend(NodeVisitor& nv)
{
std::for_each(_parents.begin(),_parents.end(),NodeAcceptOp(nv));
} void Node::setStateSet(osg::StateSet* stateset)
{
// do nothing if nothing changed.
if (_stateset==stateset) return; // track whether we need to account for the need to do a update or event traversal.
int delta_update = ;
int delta_event = ; // remove this node from the current statesets parent list
if (_stateset.valid())
{
_stateset->removeParent(this);
if (_stateset->requiresUpdateTraversal()) --delta_update;
if (_stateset->requiresEventTraversal()) --delta_event;
} // set the stateset.
_stateset = stateset; // add this node to the new stateset to the parent list.
if (_stateset.valid())
{
_stateset->addParent(this);
if (_stateset->requiresUpdateTraversal()) ++delta_update;
if (_stateset->requiresEventTraversal()) ++delta_event;
} if (delta_update!=)
{
setNumChildrenRequiringUpdateTraversal(getNumChildrenRequiringUpdateTraversal()+delta_update);
} if (delta_event!=)
{
setNumChildrenRequiringEventTraversal(getNumChildrenRequiringEventTraversal()+delta_event);
}
} osg::StateSet* Node::getOrCreateStateSet()
{
if (!_stateset) setStateSet(new StateSet);
return _stateset.get();
} NodePathList Node::getParentalNodePaths(osg::Node* haltTraversalAtNode) const
{
CollectParentPaths cpp(haltTraversalAtNode);
const_cast<Node*>(this)->accept(cpp);
return cpp._nodePaths;
} MatrixList Node::getWorldMatrices(const osg::Node* haltTraversalAtNode) const
{
CollectParentPaths cpp(haltTraversalAtNode);
const_cast<Node*>(this)->accept(cpp); MatrixList matrices; for(NodePathList::iterator itr = cpp._nodePaths.begin();
itr != cpp._nodePaths.end();
++itr)
{
NodePath& nodePath = *itr;
if (nodePath.empty())
{
matrices.push_back(osg::Matrix::identity());
}
else
{
matrices.push_back(osg::computeLocalToWorld(nodePath));
}
} return matrices;
} void Node::setUpdateCallback(Callback* nc)
{
// if no changes just return.
if (_updateCallback==nc) return; // updated callback has been changed, will need to update
// both _updateCallback and possibly the numChildrenRequiringAppTraversal
// if the number of callbacks changes. // update the parents numChildrenRequiringAppTraversal
// note, if _numChildrenRequiringUpdateTraversal!=0 then the
// parents won't be affected by any app callback change,
// so no need to inform them.
if (_numChildrenRequiringUpdateTraversal== && !_parents.empty())
{
int delta = ;
if (_updateCallback.valid()) --delta;
if (nc) ++delta;
if (delta!=)
{
// the number of callbacks has changed, need to pass this
// on to parents so they know whether app traversal is
// required on this subgraph.
for(ParentList::iterator itr =_parents.begin();
itr != _parents.end();
++itr)
{
(*itr)->setNumChildrenRequiringUpdateTraversal(
(*itr)->getNumChildrenRequiringUpdateTraversal()+delta );
} }
} // set the app callback itself.
_updateCallback = nc; } void Node::setNumChildrenRequiringUpdateTraversal(unsigned int num)
{
// if no changes just return.
if (_numChildrenRequiringUpdateTraversal==num) return; // note, if _updateCallback is set then the
// parents won't be affected by any changes to
// _numChildrenRequiringUpdateTraversal so no need to inform them.
if (!_updateCallback && !_parents.empty())
{ // need to pass on changes to parents.
int delta = ;
if (_numChildrenRequiringUpdateTraversal>) --delta;
if (num>) ++delta;
if (delta!=)
{
// the number of callbacks has changed, need to pass this
// on to parents so they know whether app traversal is
// required on this subgraph.
for(ParentList::iterator itr =_parents.begin();
itr != _parents.end();
++itr)
{
(*itr)->setNumChildrenRequiringUpdateTraversal(
(*itr)->getNumChildrenRequiringUpdateTraversal()+delta
);
} }
} // finally update this objects value.
_numChildrenRequiringUpdateTraversal=num; } void Node::setEventCallback(Callback* nc)
{
// if no changes just return.
if (_eventCallback==nc) return; // event callback has been changed, will need to Event
// both _EventCallback and possibly the numChildrenRequiringAppTraversal
// if the number of callbacks changes. // Event the parents numChildrenRequiringAppTraversal
// note, if _numChildrenRequiringEventTraversal!=0 then the
// parents won't be affected by any app callback change,
// so no need to inform them.
if (_numChildrenRequiringEventTraversal== && !_parents.empty())
{
int delta = ;
if (_eventCallback.valid()) --delta;
if (nc) ++delta;
if (delta!=)
{
// the number of callbacks has changed, need to pass this
// on to parents so they know whether app traversal is
// required on this subgraph.
for(ParentList::iterator itr =_parents.begin();
itr != _parents.end();
++itr)
{
(*itr)->setNumChildrenRequiringEventTraversal(
(*itr)->getNumChildrenRequiringEventTraversal()+delta );
} }
} // set the app callback itself.
_eventCallback = nc; } void Node::setNumChildrenRequiringEventTraversal(unsigned int num)
{
// if no changes just return.
if (_numChildrenRequiringEventTraversal==num) return; // note, if _EventCallback is set then the
// parents won't be affected by any changes to
// _numChildrenRequiringEventTraversal so no need to inform them.
if (!_eventCallback && !_parents.empty())
{ // need to pass on changes to parents.
int delta = ;
if (_numChildrenRequiringEventTraversal>) --delta;
if (num>) ++delta;
if (delta!=)
{
// the number of callbacks has changed, need to pass this
// on to parents so they know whether app traversal is
// required on this subgraph.
for(ParentList::iterator itr =_parents.begin();
itr != _parents.end();
++itr)
{
(*itr)->setNumChildrenRequiringEventTraversal(
(*itr)->getNumChildrenRequiringEventTraversal()+delta
);
} }
} // finally Event this objects value.
_numChildrenRequiringEventTraversal=num; } void Node::setCullingActive(bool active)
{
// if no changes just return.
if (_cullingActive == active) return; // culling active has been changed, will need to update
// both _cullActive and possibly the parents numChildrenWithCullingDisabled
// if culling disabled changes. // update the parents _numChildrenWithCullingDisabled
// note, if _numChildrenWithCullingDisabled!=0 then the
// parents won't be affected by any app callback change,
// so no need to inform them.
if (_numChildrenWithCullingDisabled== && !_parents.empty())
{
int delta = ;
if (!_cullingActive) --delta;
if (!active) ++delta;
if (delta!=)
{
// the number of callbacks has changed, need to pass this
// on to parents so they know whether app traversal is
// required on this subgraph.
for(ParentList::iterator itr =_parents.begin();
itr != _parents.end();
++itr)
{
(*itr)->setNumChildrenWithCullingDisabled(
(*itr)->getNumChildrenWithCullingDisabled()+delta );
} }
} // set the cullingActive itself.
_cullingActive = active;
} void Node::setNumChildrenWithCullingDisabled(unsigned int num)
{
// if no changes just return.
if (_numChildrenWithCullingDisabled==num) return; // note, if _cullingActive is false then the
// parents won't be affected by any changes to
// _numChildrenWithCullingDisabled so no need to inform them.
if (_cullingActive && !_parents.empty())
{ // need to pass on changes to parents.
int delta = ;
if (_numChildrenWithCullingDisabled>) --delta;
if (num>) ++delta;
if (delta!=)
{
// the number of callbacks has changed, need to pass this
// on to parents so they know whether app traversal is
// required on this subgraph.
for(ParentList::iterator itr =_parents.begin();
itr != _parents.end();
++itr)
{
(*itr)->setNumChildrenWithCullingDisabled(
(*itr)->getNumChildrenWithCullingDisabled()+delta
);
} }
} // finally update this objects value.
_numChildrenWithCullingDisabled=num;
} void Node::setNumChildrenWithOccluderNodes(unsigned int num)
{
// if no changes just return.
if (_numChildrenWithOccluderNodes==num) return; // note, if this node is a OccluderNode then the
// parents won't be affected by any changes to
// _numChildrenWithOccluderNodes so no need to inform them.
if (!dynamic_cast<OccluderNode*>(this) && !_parents.empty())
{ // need to pass on changes to parents.
int delta = ;
if (_numChildrenWithOccluderNodes>) --delta;
if (num>) ++delta;
if (delta!=)
{
// the number of callbacks has changed, need to pass this
// on to parents so they know whether app traversal is
// required on this subgraph.
for(ParentList::iterator itr =_parents.begin();
itr != _parents.end();
++itr)
{
(*itr)->setNumChildrenWithOccluderNodes(
(*itr)->getNumChildrenWithOccluderNodes()+delta
);
} }
} // finally update this objects value.
_numChildrenWithOccluderNodes=num; } bool Node::containsOccluderNodes() const
{
return _numChildrenWithOccluderNodes> || dynamic_cast<const OccluderNode*>(this);
} void Node::setDescriptions(const DescriptionList& descriptions)
{
// only assign a description list (and associated UseDataContainer) if we need to.
if (!descriptions.empty() || getUserDataContainer())
{
getOrCreateUserDataContainer()->setDescriptions(descriptions);
}
} Node::DescriptionList& Node::getDescriptions()
{
return getOrCreateUserDataContainer()->getDescriptions();
} static OpenThreads::Mutex s_mutex_StaticDescriptionList;
static const Node::DescriptionList& getStaticDescriptionList()
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_mutex_StaticDescriptionList);
static Node::DescriptionList s_descriptionList;
return s_descriptionList;
} const Node::DescriptionList& Node::getDescriptions() const
{
if (_userDataContainer) return _userDataContainer->getDescriptions();
else return getStaticDescriptionList();
} std::string& Node::getDescription(unsigned int i)
{
return getOrCreateUserDataContainer()->getDescriptions()[i];
} const std::string& Node::getDescription(unsigned int i) const
{
if (_userDataContainer) return _userDataContainer->getDescriptions()[i];
else return getStaticDescriptionList()[i];
} unsigned int Node::getNumDescriptions() const
{
return _userDataContainer ? _userDataContainer->getDescriptions().size() : ;
} void Node::addDescription(const std::string& desc)
{
getOrCreateUserDataContainer()->getDescriptions().push_back(desc);
} BoundingSphere Node::computeBound() const
{
return BoundingSphere();
} void Node::dirtyBound()
{
if (_boundingSphereComputed)
{
_boundingSphereComputed = false; // dirty parent bounding sphere's to ensure that all are valid.
for(ParentList::iterator itr=_parents.begin();
itr!=_parents.end();
++itr)
{
(*itr)->dirtyBound();
} }
} void Node::setThreadSafeRefUnref(bool threadSafe)
{
Object::setThreadSafeRefUnref(threadSafe); if (_stateset.valid()) _stateset->setThreadSafeRefUnref(threadSafe);
if (_updateCallback.valid()) _updateCallback->setThreadSafeRefUnref(threadSafe);
if (_eventCallback.valid()) _eventCallback->setThreadSafeRefUnref(threadSafe);
if (_cullCallback.valid()) _cullCallback->setThreadSafeRefUnref(threadSafe);
} void Node::resizeGLObjectBuffers(unsigned int maxSize)
{
if (_stateset.valid()) _stateset->resizeGLObjectBuffers(maxSize);
if (_updateCallback.valid()) _updateCallback->resizeGLObjectBuffers(maxSize);
if (_eventCallback.valid()) _eventCallback->resizeGLObjectBuffers(maxSize);
if (_cullCallback.valid()) _cullCallback->resizeGLObjectBuffers(maxSize);
} void Node::releaseGLObjects(osg::State* state) const
{
if (_stateset.valid()) _stateset->releaseGLObjects(state);
if (_updateCallback.valid()) _updateCallback->releaseGLObjects(state);
if (_eventCallback.valid()) _eventCallback->releaseGLObjects(state);
if (_cullCallback.valid()) _cullCallback->releaseGLObjects(state);
}

osg::Node源码的更多相关文章

  1. osg::Group源码

    osg::Group源码 /* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library i ...

  2. node源码详解(二 )—— 运行机制 、整体流程

    本作品采用知识共享署名 4.0 国际许可协议进行许可.转载保留声明头部与原文链接https://luzeshu.com/blog/nodesource2 本博客同步在https://cnodejs.o ...

  3. mac下编译node源码

    看过一篇win7 64x下面编译node的文章,链接地址:编译nodejs及其源码研究 下面学习一下在mac下面如何编译node源码. 过程也挺简单. 1.下载源码. > mkdir nodes ...

  4. This Node源码分析

    看军哥博客有Rtos的源码分析,手痒耍宝把自己读的源码笔记分享出来.愿与众君互相讨论学习 namespace ros { namespace names { void init(const M_str ...

  5. node源码详解(四) —— js代码如何调用C++的函数

    本作品采用知识共享署名 4.0 国际许可协议进行许可.转载保留声明头部与原文链接https://luzeshu.com/blog/nodesource4 本博客同步在https://cnodejs.o ...

  6. node源码详解(三)—— js代码在node中的位置,process、require、module、exports的由来

    本作品采用知识共享署名 4.0 国际许可协议进行许可.转载保留声明头部与原文链接https://luzeshu.com/blog/nodesource3 本博客同步在https://cnodejs.o ...

  7. node源码详解 (一)

    本作品采用知识共享署名 4.0 国际许可协议进行许可.转载保留声明头部与原文链接https://luzeshu.com/blog/nodesource1 本博客同步在https://cnodejs.o ...

  8. 放一个Dynamicinputs corresponding to Dynamicknobs的Node源码

    static const char* const CLASS = "AddInputsSol"; static const char* const HELP = "Add ...

  9. node源码详解(三)

    本作品采用知识共享署名 4.0 国际许可协议进行许可.转载保留声明头部与原文链接https://luzeshu.com/blog/nodesource3 本博客同步在https://cnodejs.o ...

随机推荐

  1. Linux kernel启动选项(参数)(转)

    Linux kernel启动选项(参数)  转载链接https://www.cnblogs.com/linuxbo/p/4286227.html 在Linux中,给kernel传递参数以控制其行为总共 ...

  2. OracleXETNSListener无法启动或启动停止

    一.修改配置文件 1. 打开oracle的安装目录,找到下述文件"listener.ora" 2. 用文本编辑器打开“listener.ora”文件,找到下图所示位置:(HOST ...

  3. 数据库开发-Django ORM的多对多查询

    数据库开发-Django ORM的多对多查询 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.联合主键问题 CREATE TABLE `employees` ( `emp_no` ...

  4. MySQL/MariaDB数据库的多表查询操作

    MySQL/MariaDB数据库的多表查询操作 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.单表查询小试牛刀 [root@node105.yinzhengjie.org.cn ...

  5. CSS选择器知识梳理

    <一>CSS选择器结构逻辑图 温馨提示:各位小伙伴,可以把逻辑图下载下来放大,看的比较清除,也可以给我留言,我分享原百度脑图给各位小伙伴. <二>接下来按照结构逻辑图具体讲解各 ...

  6. Windows 将FTP 映射到本地文件夹 --简化操作

    转载自yutiantongbu Windows 将FTP 映射到本地文件夹 --简化操作 1.右键我的电脑,选择映射网络驱动器 2.选择"连接到可用与存储文档和图片的网站" 3.接 ...

  7. 常用conda命令【转载】

    转载地址:https://haoyu.love/blog900.html 一直在用 Conda,很多东西记不住,每次都要查 Doc.那好,就写在这里做个备忘好了. 在 bash 里面自动加载 cond ...

  8. 【云栖社区001-数据结构】如何实现一个高效的单向链表逆序输出(Java版)

    如题 动手之前,发现自己很擅长用C语言来写链表. 不过,既然自己做的是Java开发,那么还是用Java实现这个算法吧:毕竟,以后的若干年里都差不多要跟Java打交道了. 于是,先将Java版的链表自学 ...

  9. 解决PHP处理图片时内存占用过高问题

    用过GD库的同学可能都知道,使用imagecreatetruecolor()函数创建一个真彩色的画布是第一步.但是,如果画布的宽高超过平常的宽高,会带来极大的内存消耗.比如,一个9600×4800的画 ...

  10. keyword (this and arguments) in function --- 涉及递归

    arguments 就像一个数组一样,包含了传递给这个函数的参数 , 以上部分为this的介绍,注意arguments.callee  属性 ,可用于递归调用,其代表的是  : 当前正在运行函数的引用 ...