Bug fix which makes applications crash when adding a renderer to an on stage actor
[platform/core/uifw/dali-core.git] / dali / internal / update / nodes / node.cpp
1 /*
2  * Copyright (c) 2014 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali/internal/update/nodes/node.h>
20
21 // INTERNAL INCLUDES
22 #include <dali/internal/update/node-attachments/node-attachment.h>
23 #include <dali/internal/update/common/discard-queue.h>
24 #include <dali/public-api/common/dali-common.h>
25 #include <dali/public-api/common/constants.h>
26
27 namespace Dali
28 {
29
30 namespace Internal
31 {
32
33 namespace SceneGraph
34 {
35
36 const PositionInheritanceMode Node::DEFAULT_POSITION_INHERITANCE_MODE( INHERIT_PARENT_POSITION );
37 const ColorMode Node::DEFAULT_COLOR_MODE( USE_OWN_MULTIPLY_PARENT_ALPHA );
38
39 Node* Node::New()
40 {
41   return new Node();
42 }
43
44 Node::Node()
45 : mParentOrigin( ParentOrigin::DEFAULT ),
46   mAnchorPoint( AnchorPoint::DEFAULT ),
47   mSize(),     // zero initialized by default
48   mPosition(), // zero initialized by default
49   mOrientation(), // initialized to identity by default
50   mScale( Vector3::ONE ),
51   mVisible( true ),
52   mColor( Color::WHITE ),
53   mWorldPosition(), // zero initialized by default
54   mWorldOrientation(), // initialized to identity by default
55   mWorldScale( Vector3::ONE ),
56   mWorldMatrix(),
57   mWorldColor( Color::WHITE ),
58   mParent( NULL ),
59   mExclusiveRenderTask( NULL ),
60   mAttachment( NULL ),
61   mChildren(),
62   mDirtyFlags(AllFlags),
63   mIsRoot( false ),
64   mInheritOrientation( true ),
65   mInheritScale( true ),
66   mInhibitLocalTransform( false ),
67   mIsActive( true ),
68   mDrawMode( DrawMode::NORMAL ),
69   mPositionInheritanceMode( DEFAULT_POSITION_INHERITANCE_MODE ),
70   mColorMode( DEFAULT_COLOR_MODE )
71 {
72 }
73
74 Node::~Node()
75 {
76 }
77
78 void Node::OnDestroy()
79 {
80   // Node attachments should be notified about the disconnection.
81   if ( mAttachment )
82   {
83     mAttachment->OnDestroy();
84   }
85
86   // Animators, Constraints etc. should be disconnected from the child's properties.
87   PropertyOwner::Destroy();
88 }
89
90 void Node::Attach( NodeAttachment& object )
91 {
92   DALI_ASSERT_DEBUG(!mAttachment);
93
94   object.SetParent(*this);
95
96   mAttachment = &object;
97   SetAllDirtyFlags();
98
99   if( mIsActive )
100   {
101     mAttachment->ConnectedToSceneGraph();
102   }
103 }
104
105 void Node::SetRoot(bool isRoot)
106 {
107   DALI_ASSERT_DEBUG(!isRoot || mParent == NULL); // Root nodes cannot have a parent
108
109   mIsRoot = isRoot;
110 }
111
112 void Node::ConnectChild( Node* childNode, int index )
113 {
114   DALI_ASSERT_ALWAYS( this != childNode );
115   DALI_ASSERT_ALWAYS( IsRoot() || NULL != mParent ); // Parent should be connected first
116   DALI_ASSERT_ALWAYS( !childNode->IsRoot() && NULL == childNode->GetParent() ); // Child should be disconnected
117
118   childNode->SetParent( *this );
119
120   // Everything should be reinherited when reconnected to scene-graph
121   childNode->SetAllDirtyFlags();
122
123   if (index == -1)
124   {
125     mChildren.PushBack( childNode );
126   }
127   else
128   {
129     mChildren.Insert(mChildren.Begin()+index, childNode);
130   }
131
132   // Inform property observers of new connection
133   childNode->ConnectToSceneGraph();
134
135   // Inform child node attachment that the node has been added to the stage
136   if( childNode->mAttachment )
137   {
138     childNode->mAttachment->ConnectedToSceneGraph();
139   }
140 }
141
142 void Node::DisconnectChild( BufferIndex updateBufferIndex, Node& childNode, std::set<Node*>& connectedNodes,  std::set<Node*>& disconnectedNodes )
143 {
144   DALI_ASSERT_ALWAYS( this != &childNode );
145   DALI_ASSERT_ALWAYS( childNode.GetParent() == this );
146
147   // Find the childNode and remove it
148   Node* found( NULL );
149
150   const NodeIter endIter = mChildren.End();
151   for ( NodeIter iter = mChildren.Begin(); iter != endIter; ++iter )
152   {
153     Node* current = *iter;
154     if ( current == &childNode )
155     {
156       found = current;
157       mChildren.Erase( iter ); // order matters here
158       break; // iter is no longer valid
159     }
160   }
161   DALI_ASSERT_ALWAYS( NULL != found );
162
163   found->RecursiveDisconnectFromSceneGraph( updateBufferIndex, connectedNodes, disconnectedNodes );
164 }
165
166 int Node::GetDirtyFlags() const
167 {
168   // get initial dirty flags, they are reset ResetDefaultProperties, but setters may have made the node dirty already
169   int flags = mDirtyFlags;
170   const bool sizeFlag = mSize.IsClean();
171
172   if ( !(flags & TransformFlag) )
173   {
174     // Check whether the transform related properties have changed
175     if( !sizeFlag            ||
176         !mPosition.IsClean() ||
177         !mOrientation.IsClean() ||
178         !mScale.IsClean()    ||
179         mParentOrigin.InputChanged() || // parent origin and anchor point rarely change
180         mAnchorPoint.InputChanged() )
181     {
182       flags |= TransformFlag;
183     }
184   }
185
186   // Check whether the visible property has changed
187   if ( !mVisible.IsClean() )
188   {
189     flags |= VisibleFlag;
190   }
191
192   // Check whether the color property has changed
193   if ( !mColor.IsClean() )
194   {
195     flags |= ColorFlag;
196   }
197
198   // Check whether the size property has changed
199   if ( !sizeFlag )
200   {
201     flags |= SizeFlag;
202    }
203
204   return flags;
205 }
206
207 void Node::ResetDefaultProperties( BufferIndex updateBufferIndex )
208 {
209   // clear dirty flags in parent origin & anchor point
210   mParentOrigin.Clear();
211   mAnchorPoint.Clear();
212   // Reset default properties
213   mSize.ResetToBaseValue( updateBufferIndex );
214   mPosition.ResetToBaseValue( updateBufferIndex );
215   mOrientation.ResetToBaseValue( updateBufferIndex );
216   mScale.ResetToBaseValue( updateBufferIndex );
217   mVisible.ResetToBaseValue( updateBufferIndex );
218   mColor.ResetToBaseValue( updateBufferIndex );
219
220   mDirtyFlags = NothingFlag;
221 }
222
223 bool Node::IsFullyVisible( BufferIndex updateBufferIndex ) const
224 {
225   if( !IsVisible( updateBufferIndex ) )
226   {
227     return false;
228   }
229
230   Node* parent = mParent;
231
232   while( NULL != parent )
233   {
234     if( !parent->IsVisible( updateBufferIndex ) )
235     {
236       return false;
237     }
238
239     parent = parent->GetParent();
240   }
241
242   return true;
243 }
244
245 void Node::SetParent(Node& parentNode)
246 {
247   DALI_ASSERT_ALWAYS(this != &parentNode);
248   DALI_ASSERT_ALWAYS(!mIsRoot);
249   DALI_ASSERT_ALWAYS(mParent == NULL);
250
251   mParent = &parentNode;
252 }
253
254 void Node::RecursiveDisconnectFromSceneGraph( BufferIndex updateBufferIndex, std::set<Node*>& connectedNodes,  std::set<Node*>& disconnectedNodes )
255 {
256   DALI_ASSERT_ALWAYS(!mIsRoot);
257   DALI_ASSERT_ALWAYS(mParent != NULL);
258
259   const NodeIter endIter = mChildren.End();
260   for ( NodeIter iter = mChildren.Begin(); iter != endIter; ++iter )
261   {
262     (*iter)->RecursiveDisconnectFromSceneGraph( updateBufferIndex, connectedNodes, disconnectedNodes );
263   }
264
265   // Animators, Constraints etc. should be disconnected from the child's properties.
266   PropertyOwner::DisconnectFromSceneGraph( updateBufferIndex );
267
268   // Remove back-pointer to parent
269   mParent = NULL;
270
271   // Remove all child pointers
272   mChildren.Clear();
273
274   // Inform child node attachment that the node has been removed from the stage
275   if( mAttachment )
276   {
277     mAttachment->DisconnectedFromSceneGraph();
278   }
279
280   // Move into disconnectedNodes
281   std::set<Node*>::size_type removed = connectedNodes.erase( this );
282   DALI_ASSERT_ALWAYS( removed );
283   disconnectedNodes.insert( this );
284 }
285
286 } // namespace SceneGraph
287
288 } // namespace Internal
289
290 } // namespace Dali