summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--slideshow/source/engine/animationnodes/animationnodefactory.cxx638
1 files changed, 638 insertions, 0 deletions
diff --git a/slideshow/source/engine/animationnodes/animationnodefactory.cxx b/slideshow/source/engine/animationnodes/animationnodefactory.cxx
new file mode 100644
index 000000000000..aa1845f36e70
--- /dev/null
+++ b/slideshow/source/engine/animationnodes/animationnodefactory.cxx
@@ -0,0 +1,638 @@
+/*************************************************************************
+ *
+ * $RCSfile: animationnodefactory.cxx,v $
+ *
+ * $Revision: 1.2 $
+ *
+ * last change: $Author: kz $ $Date: 2005-01-21 17:02:44 $
+ *
+ * The Contents of this file are made available subject to the terms of
+ * either of the following licenses
+ *
+ * - GNU Lesser General Public License Version 2.1
+ * - Sun Industry Standards Source License Version 1.1
+ *
+ * Sun Microsystems Inc., October, 2000
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2000 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * 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 GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ *
+ * Sun Industry Standards Source License Version 1.1
+ * =================================================
+ * The contents of this file are subject to the Sun Industry Standards
+ * Source License Version 1.1 (the "License"); You may not use this file
+ * except in compliance with the License. You may obtain a copy of the
+ * License at http://www.openoffice.org/license.html.
+ *
+ * Software provided under this License is provided on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
+ * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
+ * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
+ * See the License for the specific provisions governing your rights and
+ * obligations concerning the Software.
+ *
+ * The Initial Developer of the Original Code is: Sun Microsystems, Inc.
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * All Rights Reserved.
+ *
+ * Contributor(s): _______________________________________
+ *
+ *
+ ************************************************************************/
+
+// must be first
+#include <canvas/debug.hxx>
+#include <canvas/verbosetrace.hxx>
+
+#include <animationnodefactory.hxx>
+#include <paralleltimecontainer.hxx>
+#include <sequentialtimecontainer.hxx>
+#include <propertyanimationnode.hxx>
+#include <animationsetnode.hxx>
+#include <animationpathmotionnode.hxx>
+#include <animationcolornode.hxx>
+#include <animationtransformnode.hxx>
+#include <animationtransitionfilternode.hxx>
+#include <animationaudionode.hxx>
+#include <nodetools.hxx>
+#include <tools.hxx>
+
+#include <animations/animationnodehelper.hxx>
+
+#ifndef _COM_SUN_STAR_DRAWING_XSHAPE_HPP_
+#include <com/sun/star/drawing/XShape.hpp>
+#endif
+#ifndef _COM_SUN_STAR_ANIMATIONS_XANIMATE_HPP_
+#include <com/sun/star/animations/XAnimate.hpp>
+#endif
+#ifndef _COM_SUN_STAR_ANIMATIONS_ANIMATIONNODETYPE_HPP_
+#include <com/sun/star/animations/AnimationNodeType.hpp>
+#endif
+#ifndef _COM_SUN_STAR_PRESENTATION_EFFECTNODETYPE_HPP_
+#include <com/sun/star/presentation/EffectNodeType.hpp>
+#endif
+#ifndef _COM_SUN_STAR_PRESENTATION_TEXTANIMATIONTYPE_HPP_
+#include <com/sun/star/presentation/TextAnimationType.hpp>
+#endif
+#ifndef _COM_SUN_STAR_ANIMATIONS_XANIMATESET_HPP_
+#include <com/sun/star/animations/XAnimateSet.hpp>
+#endif
+#ifndef _COM_SUN_STAR_ANIMATIONS_XITERATECONTAINER_HPP_
+#include <com/sun/star/animations/XIterateContainer.hpp>
+#endif
+#ifndef _COM_SUN_STAR_PRESENTATION_SHAPEANIMATIONSUBTYPE_HPP_
+#include <com/sun/star/presentation/ShapeAnimationSubType.hpp>
+#endif
+#ifndef _COM_SUN_STAR_ANIMATIONS_XANIMATEMOTION_HPP_
+#include <com/sun/star/animations/XAnimateMotion.hpp>
+#endif
+#ifndef _COM_SUN_STAR_ANIMATIONS_XANIMATECOLOR_HPP_
+#include <com/sun/star/animations/XAnimateColor.hpp>
+#endif
+#ifndef _COM_SUN_STAR_ANIMATIONS_XANIMATETRANSFORM_HPP_
+#include <com/sun/star/animations/XAnimateTransform.hpp>
+#endif
+#ifndef _COM_SUN_STAR_ANIMATIONS_ANIMATIONTRANSFORMTYPE_HPP_
+#include <com/sun/star/animations/AnimationTransformType.hpp>
+#endif
+#ifndef _COM_SUN_STAR_ANIMATIONS_XTRANSITIONFILTER_HPP_
+#include <com/sun/star/animations/XTransitionFilter.hpp>
+#endif
+#ifndef _COM_SUN_STAR_ANIMATIONS_XAUDIO_HPP_
+#include <com/sun/star/animations/XAudio.hpp>
+#endif
+#ifndef _COM_SUN_STAR_PRESENTATION_PARAGRAPHTARGET_HPP_
+#include <com/sun/star/presentation/ParagraphTarget.hpp>
+#endif
+#ifndef _COM_SUN_STAR_BEANS_XPROPERTYSET_HPP_
+#include <com/sun/star/beans/XPropertySet.hpp>
+#endif
+
+#ifndef _BGFX_NUMERIC_FTOOLS_HXX
+#include <basegfx/numeric/ftools.hxx>
+#endif
+
+#ifndef BOOST_BIND_HPP_INCLUDED
+#include <boost/bind.hpp>
+#endif
+#ifndef BOOST_MEM_FN_HPP_INCLUDED
+#include <boost/mem_fn.hpp>
+#endif
+
+#include <vector>
+#include <algorithm>
+#include <iterator>
+
+using namespace ::com::sun::star;
+
+namespace presentation
+{
+ namespace internal
+ {
+ namespace
+ {
+ // forward declaration needed by NodeCreator
+ BaseNodeSharedPtr implCreateAnimationNode( const uno::Reference< animations::XAnimationNode >& xNode,
+ const BaseContainerNodeSharedPtr& rParent,
+ const NodeContext& rContext );
+
+ class NodeCreator
+ {
+ public:
+ NodeCreator( BaseContainerNodeSharedPtr& rParent,
+ const NodeContext& rContext ) :
+ mrParent( rParent ),
+ mrContext( rContext )
+ {
+ }
+
+ void operator()( const uno::Reference< animations::XAnimationNode >& xChildNode ) const
+ {
+ createChild( xChildNode, mrContext );
+ }
+
+ protected:
+ void createChild( const uno::Reference< animations::XAnimationNode >& xChildNode,
+ const NodeContext& rContext ) const
+ {
+ BaseNodeSharedPtr pChild( implCreateAnimationNode( xChildNode,
+ mrParent,
+ rContext ) );
+
+ OSL_ENSURE( pChild.get(), "NodeCreator::operator(): child creation failed" );
+
+ // TODO(Q1): This yields circular references, which, it seems, is
+ // unavoidable here
+ if( pChild.get() )
+ mrParent->appendChildNode( pChild );
+ }
+
+ BaseContainerNodeSharedPtr& mrParent;
+ const NodeContext& mrContext;
+ };
+
+ /** Same as NodeCreator, only that NodeContext's
+ SubsetShape is cloned for every child node.
+
+ This is used for iterated animation node generation
+ */
+ class CloningNodeCreator : private NodeCreator
+ {
+ public:
+ CloningNodeCreator( BaseContainerNodeSharedPtr& rParent,
+ const NodeContext& rContext ) :
+ NodeCreator( rParent, rContext )
+ {
+ }
+
+ void operator()( const uno::Reference< animations::XAnimationNode >& xChildNode ) const
+ {
+ NodeContext aContext( mrContext );
+
+ // TODO(Q1): There's a catch here. If you clone a
+ // subset whose actual subsetting has already been
+ // realized (i.e. if enableSubsetShape() has been
+ // called already), and the original of your clone
+ // goes out of scope, then your subset will be
+ // gone (LayerManager::revokeSubset() be
+ // called). As of now, this behaviour is not
+ // triggered here (we either clone, XOR we enable
+ // subset initially), but one might consider
+ // reworking DrawShape/ShapeSubset to avoid this.
+
+ // clone ShapeSubset, since each node needs their
+ // own version of the ShapeSubset (otherwise,
+ // e.g. activity counting does not work - subset
+ // would be removed after first animation node
+ // disables it).
+ //
+ // NOTE: this is only a problem for animation
+ // nodes that explicitely call
+ // disableSubsetShape(). Independent shape subsets
+ // (like those created for ParagraphTargets)
+ // solely rely on the ShapeSubset destructor to
+ // normalize things, which does the right thing
+ // here: the subset is only removed after _the
+ // last_ animation node releases the shared ptr.
+ aContext.mpMasterShapeSubset.reset(
+ new ShapeSubset( *aContext.mpMasterShapeSubset ) );
+
+ createChild( xChildNode, aContext );
+ }
+ };
+
+ bool implCreateIteratedNodes( const uno::Reference< animations::XIterateContainer >& xIterNode,
+ BaseContainerNodeSharedPtr& rParent,
+ const NodeContext& rContext )
+ {
+ ENSURE_AND_THROW( xIterNode.is(),
+ "implCreateIteratedNodes(): Invalid node" );
+
+ // TODO(F2): getIterateInterval() yields a procentual time shift.
+ // Currently, we're assuming 2 seconds total animation runtime,
+ // which might of course be totally wrong.
+ const double nIntervalTimeout( xIterNode->getIterateInterval() / 50.0 );
+
+
+ // valid iterate interval? We're ruling out monstrous
+ // values here, to avoid pseudo 'hangs' in the
+ // presentation
+ if( nIntervalTimeout < 0.0 ||
+ nIntervalTimeout > 1000.0 )
+ {
+ return false; // not an active iteration
+ }
+
+ if( ::basegfx::fTools::equalZero( nIntervalTimeout ) )
+ OSL_TRACE( "implCreateIteratedNodes(): iterate interval close to zero, there's "
+ "no point in defining such an effect (visually equivalent to whole-shape effect)" );
+
+ // Determine target shape (or subset)
+ // ==================================
+
+ // TODO(E1): I'm not too sure what to expect here...
+ ENSURE_AND_RETURN( xIterNode->getTarget().hasValue(),
+ "implCreateIteratedNodes(): no target on ITERATE node" );
+
+ uno::Reference< drawing::XShape > xTargetShape( xIterNode->getTarget(),
+ uno::UNO_QUERY );
+
+ ::com::sun::star::presentation::ParagraphTarget aTarget;
+ sal_Int16 nSubItem( xIterNode->getSubItem() );
+ bool bParagraphTarget( false );
+
+ if( !xTargetShape.is() )
+ {
+ // no shape provided. Maybe a ParagraphTarget?
+ if( !(xIterNode->getTarget() >>= aTarget) )
+ ENSURE_AND_RETURN( false,
+ "implCreateIteratedNodes(): could not extract any "
+ "target information" );
+
+ xTargetShape = aTarget.Shape;
+
+ ENSURE_AND_RETURN( xTargetShape.is(),
+ "implCreateIteratedNodes(): invalid shape in ParagraphTarget" );
+
+ // we've a paragraph target to iterate over, thus,
+ // the whole animation container refers only to
+ // the text
+ nSubItem = ::com::sun::star::presentation::ShapeAnimationSubType::ONLY_TEXT;
+
+ bParagraphTarget = true;
+ }
+
+
+ // Lookup shape, and fill NodeContext
+ // ==================================
+
+ AttributableShapeSharedPtr pTargetShape(
+ lookupAttributableShape( rContext.maContext.mpLayerManager,
+ xTargetShape ) );
+ ShapeSubsetSharedPtr pTargetSubset;
+
+ NodeContext aContext( rContext );
+
+ // paragraph targets already need a subset as the
+ // master shape (they're representing only a single
+ // paragraph)
+ if( bParagraphTarget )
+ {
+ pTargetSubset.reset(
+ new ShapeSubset(
+ pTargetShape,
+ DocTreeNode::createFromShape(
+ pTargetShape,
+ aTarget.Paragraph,
+ DocTreeNode::NODETYPE_LOGICAL_PARAGRAPH ),
+ rContext.maContext.mpLayerManager ));
+
+ // iterate target is not the whole shape, but only
+ // the selected paragraph - subset _must_ be
+ // independent, to be able to affect visibility
+ // independent of master shape
+ aContext.mbIsIndependentSubset = true;
+
+ // already enable parent subset right here, to
+ // make potentially generated subsets subtract
+ // their content from the parent subset (and not
+ // the original shape). Otherwise, already
+ // subsetted parents (e.g. paragraphs) would not
+ // have their characters removed, when the child
+ // iterations start.
+ // Furthermore, the setup of initial shape
+ // attributes of course needs the subset shape
+ // generated, to apply e.g. visibility changes.
+ pTargetSubset->enableSubsetShape();
+ }
+ else
+ {
+ pTargetSubset.reset(
+ new ShapeSubset( pTargetShape,
+ rContext.maContext.mpLayerManager ) );
+ }
+
+ aContext.mpMasterShapeSubset = pTargetSubset;
+ uno::Reference< animations::XAnimationNode > xNode( xIterNode,
+ uno::UNO_QUERY_THROW );
+
+
+ // Generate subsets
+ // ================
+
+ if( bParagraphTarget ||
+ nSubItem != ::com::sun::star::presentation::ShapeAnimationSubType::ONLY_TEXT )
+ {
+ // prepend with animations for
+ // full Shape (will be subtracted
+ // from the subset parts within
+ // the Shape::createSubset()
+ // method). For ONLY_TEXT effects,
+ // we skip this part, to animate
+ // only the text.
+ //
+ // OR
+ //
+ // prepend with subset animation for full
+ // _paragraph_, from which the individual
+ // paragraph subsets are subtracted. Note that the
+ // subitem is superfluous here, we always assume
+ // ONLY_TEXT, if a paragraph is referenced as the
+ // master of an iteration effect.
+ NodeCreator aCreator( rParent, aContext );
+ if( !::anim::for_each_childNode( xNode,
+ aCreator ) )
+ {
+ ENSURE_AND_RETURN( false,
+ "implCreateIteratedNodes(): iterated child node creation failed" );
+ }
+ }
+
+ // TODO(F2): This does not do the correct
+ // thing. Having nSubItem be set to ONLY_BACKGROUND
+ // should result in the text staying unanimated in the
+ // foreground, while the shape moves in the background
+ // (this behaviour is perfectly possible with the
+ // slideshow engine, only that the text won't be
+ // currently visible, because animations are always in
+ // the foreground)
+ if( pTargetSubset->getSubsetShape()->getNumberOfTreeNodes() > 0 &&
+ nSubItem != ::com::sun::star::presentation::ShapeAnimationSubType::ONLY_BACKGROUND )
+ {
+ // determine type of subitem iteration (logical
+ // text unit to animate)
+ DocTreeNode::NodeType eIterateNodeType(
+ DocTreeNode::NODETYPE_LOGICAL_CHARACTER_CELL );
+
+ switch( xIterNode->getIterateType() )
+ {
+ case ::com::sun::star::presentation::TextAnimationType::BY_PARAGRAPH:
+ eIterateNodeType = DocTreeNode::NODETYPE_LOGICAL_PARAGRAPH;
+ break;
+
+ case ::com::sun::star::presentation::TextAnimationType::BY_WORD:
+ eIterateNodeType = DocTreeNode::NODETYPE_LOGICAL_WORD;
+ break;
+
+ case ::com::sun::star::presentation::TextAnimationType::BY_LETTER:
+ eIterateNodeType = DocTreeNode::NODETYPE_LOGICAL_CHARACTER_CELL;
+ break;
+
+ default:
+ ENSURE_AND_THROW(false,
+ "implCreateIteratedNodes(): Unexpected IterateType on XIterateContainer");
+ break;
+ }
+
+ if( bParagraphTarget &&
+ eIterateNodeType != DocTreeNode::NODETYPE_LOGICAL_WORD &&
+ eIterateNodeType != DocTreeNode::NODETYPE_LOGICAL_CHARACTER_CELL )
+ {
+ // will not animate the whole paragraph, when
+ // only the paragraph is animated at all.
+ OSL_ENSURE( false,
+ "implCreateIteratedNodes(): Ignoring paragraph iteration for paragraph master" );
+ }
+ else
+ {
+ // setup iteration parameters
+ // --------------------------
+
+ // iterate target is the whole shape (or the
+ // whole parent subshape), thus, can save
+ // loads of subset shapes by generating them
+ // only when the effects become active -
+ // before and after the effect active
+ // duration, all attributes are shared by
+ // master shape and subset (since the iterated
+ // effects are all the same).
+ aContext.mbIsIndependentSubset = false;
+
+ // create document tree for given subitem type
+ DocTreeNode::VectorOfDocTreeNodes aTreeNodes;
+ if( bParagraphTarget )
+ {
+ // create the iterated subset _relative_ to
+ // the given paragraph index (i.e. animate the
+ // given subset type, but only when it's part
+ // of the given paragraph)
+ generateSubsets( aTreeNodes,
+ pTargetShape,
+ eIterateNodeType,
+ aTarget.Paragraph );
+ }
+ else
+ {
+ // generate normal subset
+ generateSubsets( aTreeNodes,
+ pTargetShape,
+ eIterateNodeType );
+ }
+
+
+ // iterate node, generate copies of the children for each subset
+ // -------------------------------------------------------------
+
+ const ::std::size_t nTreeNodeChildren( aTreeNodes.size() );
+
+ // NodeContext::mnStartDelay contains additional node delay. This will
+ // make the duplicated nodes for each iteration start increasingly later.
+ aContext.mnStartDelay = nIntervalTimeout;
+
+ for( ::std::size_t i=0; i<nTreeNodeChildren; ++i )
+ {
+ // TODO(F1): This might not always be correct (e.g. if there's
+ // geometry inbetween the text output)
+
+ // create subset with the corresponding tree nodes
+ aContext.mpMasterShapeSubset.reset(
+ new ShapeSubset( pTargetSubset,
+ aTreeNodes[i] ) );
+
+ CloningNodeCreator aCreator( rParent, aContext );
+ if( !::anim::for_each_childNode( xNode,
+ aCreator ) )
+ {
+ ENSURE_AND_RETURN( false,
+ "implCreateIteratedNodes(): iterated child node creation failed" );
+ }
+
+ aContext.mnStartDelay += nIntervalTimeout;
+ }
+ }
+ }
+
+ // done with iterate child generation
+ return true;
+ }
+
+ BaseNodeSharedPtr implCreateAnimationNode( const uno::Reference< animations::XAnimationNode >& xNode,
+ const BaseContainerNodeSharedPtr& rParent,
+ const NodeContext& rContext )
+ {
+ ENSURE_AND_THROW( xNode.is(), "implCreateAnimationNode(): invalid XAnimationNode" );
+
+ BaseNodeSharedPtr pCreatedNode;
+ BaseContainerNodeSharedPtr pCreatedContainer;
+
+ // create the internal node, corresponding to xNode
+ switch( xNode->getType() )
+ {
+ case animations::AnimationNodeType::CUSTOM:
+ OSL_ENSURE( false, "implCreateAnimationNode(): CUSTOM not yet implemented" );
+ return pCreatedNode;
+
+ case animations::AnimationNodeType::PAR:
+ pCreatedNode = pCreatedContainer = BaseContainerNodeSharedPtr( new ParallelTimeContainer( xNode, rParent, rContext ) );
+ break;
+
+ case animations::AnimationNodeType::ITERATE:
+ // map iterate container to ParallelTimeContainer.
+ // the iterating functionality is to be found
+ // below, (see method implCreateIteratedNodes)
+ pCreatedNode = pCreatedContainer = BaseContainerNodeSharedPtr( new ParallelTimeContainer( xNode, rParent, rContext ) );
+ break;
+
+ case animations::AnimationNodeType::SEQ:
+ pCreatedNode = pCreatedContainer = BaseContainerNodeSharedPtr( new SequentialTimeContainer( xNode, rParent, rContext ) );
+ break;
+
+ case animations::AnimationNodeType::ANIMATE:
+ pCreatedNode.reset( new PropertyAnimationNode( xNode, rParent, rContext ) );
+ break;
+
+ case animations::AnimationNodeType::SET:
+ pCreatedNode.reset( new AnimationSetNode( xNode, rParent, rContext ) );
+ break;
+
+ case animations::AnimationNodeType::ANIMATEMOTION:
+ pCreatedNode.reset( new AnimationPathMotionNode( xNode, rParent, rContext ) );
+ break;
+
+ case animations::AnimationNodeType::ANIMATECOLOR:
+ pCreatedNode.reset( new AnimationColorNode( xNode, rParent, rContext ) );
+ break;
+
+ case animations::AnimationNodeType::ANIMATETRANSFORM:
+ pCreatedNode.reset( new AnimationTransformNode( xNode, rParent, rContext ) );
+ break;
+
+ case animations::AnimationNodeType::TRANSITIONFILTER:
+ pCreatedNode.reset( new AnimationTransitionFilterNode( xNode, rParent, rContext ) );
+ break;
+
+ case animations::AnimationNodeType::AUDIO:
+ pCreatedNode.reset( new AnimationAudioNode( xNode, rParent, rContext ) );
+ break;
+
+ default:
+ OSL_ENSURE( false, "implCreateAnimationNode(): invalid AnimationNodeType" );
+ return pCreatedNode;
+ }
+
+ // TODO(Q1): This yields circular references, which, it seems, is
+ // unavoidable here
+
+ // HACK: node objects need shared_ptr to themselves,
+ // which we pass them here.
+ pCreatedNode->setSelf( pCreatedNode );
+
+ // if we've got a container node object, recursively add
+ // its children
+ if( pCreatedContainer.get() )
+ {
+ uno::Reference< animations::XIterateContainer > xIterNode( xNode,
+ uno::UNO_QUERY );
+
+ // when this node is an XIterateContainer with
+ // active iterations, this method will generate
+ // the appropriate children
+ if( xIterNode.is() )
+ {
+ // note that implCreateIteratedNodes() might
+ // choose not to generate any child nodes
+ // (e.g. when the iterate timeout is outside
+ // sensible limits). Then, no child nodes are
+ // generated at all, since typically, child
+ // node attribute are incomplete for iteration
+ // children.
+ implCreateIteratedNodes( xIterNode,
+ pCreatedContainer,
+ rContext );
+ }
+ else
+ {
+ // no iterate subset node, just plain child generation now
+ NodeCreator aCreator( pCreatedContainer, rContext );
+ if( !::anim::for_each_childNode( xNode,
+ aCreator ) )
+ {
+ OSL_ENSURE( false,
+ "implCreateAnimationNode(): child node creation failed" );
+ return BaseNodeSharedPtr();
+ }
+ }
+ }
+
+ return pCreatedNode;
+ }
+ }
+
+ AnimationNodeSharedPtr AnimationNodeFactory::createAnimationNode( const uno::Reference< animations::XAnimationNode >& xNode,
+ const SlideShowContext& rContext )
+ {
+ ENSURE_AND_THROW( xNode.is(), "AnimationNodeFactory::createAnimationNode(): invalid XAnimationNode" );
+
+ return BaseNodeSharedPtr( implCreateAnimationNode( xNode,
+ BaseContainerNodeSharedPtr(), // no parent
+ NodeContext( rContext ) ) );
+ }
+
+#if defined(VERBOSE) && defined(DBG_UTIL)
+ void AnimationNodeFactory::showTree( AnimationNodeSharedPtr& pRootNode )
+ {
+ if( pRootNode.get() )
+ DEBUG_NODES_SHOWTREE( dynamic_cast<BaseContainerNode*>( pRootNode.get() ) );
+ }
+#endif
+ }
+}