36cc8d28d5e4fd7567ff6f0c638c41bd0b607ac5
[platform/core/uifw/dali-core.git] / dali / internal / event / actor-attachments / mesh-attachment-impl.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/event/actor-attachments/mesh-attachment-impl.h>
20
21 // INTERNAL INCLUDES
22 #include <dali/public-api/common/dali-common.h>
23 #include <dali/internal/update/node-attachments/scene-graph-mesh-attachment.h>
24 #include <dali/internal/update/modeling/scene-graph-material.h>
25 #include <dali/internal/event/common/stage-impl.h>
26 #include <dali/internal/update/nodes/node.h>
27
28 using Dali::Internal::MeshIPtr;
29 using Dali::Internal::MaterialIPtr;
30
31 namespace Dali
32 {
33
34 namespace Internal
35 {
36
37 MeshAttachmentPtr MeshAttachment::New( Stage& stage, const SceneGraph::Node& parentNode )
38 {
39   MeshAttachmentPtr attachment( new MeshAttachment( stage ) );
40
41   // Transfer object ownership of scene-object to message
42   SceneGraph::MeshAttachment* sceneObject = SceneGraph::MeshAttachment::New();
43   AttachToNodeMessage( stage.GetUpdateManager(), parentNode, sceneObject );
44
45   // Keep raw pointer for message passing
46   attachment->mSceneObject = sceneObject;
47
48   return attachment;
49 }
50
51 MeshAttachment::MeshAttachment( Stage& stage )
52 : RenderableAttachment( stage ),
53   mSceneObject( NULL ),
54   mAffectedByLighting( true )
55 {
56 }
57
58 MeshAttachment::~MeshAttachment()
59 {
60   // Belt and braces - should already have been disconnected from stage
61   if ( Stage::IsInstalled() &&
62        OnStage() )
63   {
64     DisconnectMaterial();
65   }
66 }
67
68 void MeshAttachment::SetMesh( const MeshIPtr        meshPtr,
69                               ResourceId            meshId,
70                               const BoneContainer&  bones,
71                               const MaterialIPtr    material )
72 {
73   mMesh.mMesh = meshPtr;
74   mMesh.mCustomMaterial = 0;
75
76   std::size_t boneCount = bones.size();
77
78   if ( boneCount > 0 )
79   {
80     // Copy bone names locally in order to perform actor binding later
81
82     // Must keep names in same order (vertices reference into bone matrix array by index)
83     for ( BoneContainer::const_iterator iter = bones.begin(); iter != bones.end(); ++iter )
84     {
85       const Bone& bone = (*iter);
86       mMesh.mBoneNames.push_back( bone.GetName() );
87     }
88   }
89
90   mMesh.mMaterial = material;
91   const SceneGraph::Material* materialSceneObject = material->GetSceneObject();
92
93   // sceneObject is being used in a separate thread; queue a message to set
94   SetMeshMessage( mStage->GetUpdateInterface(), *mSceneObject, meshId, materialSceneObject, boneCount );
95 }
96
97 void MeshAttachment::SetMesh( const ResourceTicketPtr ticket,
98                               const BoneContainer& bones,
99                               const MaterialIPtr material )
100 {
101   SetMesh( 0, ticket->GetId(), bones, material );
102 }
103
104 void MeshAttachment::SetMaterial( MaterialIPtr material )
105 {
106   const SceneGraph::Material* materialSceneObject = NULL;
107
108   if ( material )
109   {
110     // We have a new material.
111     if ( OnStage() )
112     {
113       DisconnectMaterial();
114
115       // connect the new material
116       material->Connect();
117     }
118
119     mMesh.mCustomMaterial = material;
120
121     materialSceneObject = material->GetSceneObject();
122     DALI_ASSERT_DEBUG( materialSceneObject != NULL );
123   }
124   else
125   {
126     // We are unsetting the current material, and reverting to the original material
127     if ( mMesh.mCustomMaterial )
128     {
129       if ( OnStage() )
130       {
131         mMesh.mCustomMaterial->Disconnect();
132       }
133       mMesh.mCustomMaterial = NULL;
134     }
135
136     // connect original material
137     DALI_ASSERT_DEBUG( mMesh.mMaterial );
138
139     if ( OnStage() )
140     {
141       mMesh.mMaterial->Connect();
142     }
143     materialSceneObject = mMesh.mMaterial->GetSceneObject();
144   }
145
146   if ( OnStage() )
147   {
148     // sceneObject is being used in a separate thread; queue a message to set
149     SetMaterialMessage( mStage->GetUpdateInterface(), *mSceneObject, materialSceneObject );
150   }
151 }
152
153 Internal::MaterialIPtr MeshAttachment::GetMaterial( ) const
154 {
155   Internal::MaterialIPtr material;
156
157   if ( mMesh.mCustomMaterial )
158   {
159     material = mMesh.mCustomMaterial;
160   }
161   else if ( mMesh.mMaterial )
162   {
163     material = mMesh.mMaterial;
164   }
165   return material;
166 }
167
168
169 void MeshAttachment::DisconnectMaterial()
170 {
171   if ( mMesh.mCustomMaterial )
172   {
173     mMesh.mCustomMaterial->Disconnect();
174   }
175   else if ( mMesh.mMaterial )
176   {
177     mMesh.mMaterial->Disconnect();
178   }
179 }
180
181 void MeshAttachment::SetAffectedByLighting( bool affectedByLighting )
182 {
183   // sceneObject is being used in a separate thread; queue a message to set
184   SetAffectedByLightingMessage( mStage->GetUpdateInterface(), *mSceneObject, affectedByLighting );
185
186   mAffectedByLighting = affectedByLighting;
187 }
188
189 bool MeshAttachment::IsAffectedByLighting()
190 {
191   return mAffectedByLighting;
192 }
193
194 void MeshAttachment::BindBonesToMesh( Internal::ActorPtr rootActor )
195 {
196   size_t boneIdx = 0;
197   size_t boneCount = mMesh.mBoneNames.size();
198
199   if ( boneCount > 0 )
200   {
201     for ( BoneNamesIter boneIter=mMesh.mBoneNames.begin(); boneIter != mMesh.mBoneNames.end(); ++boneIter )
202     {
203       ActorPtr boneActor = rootActor->FindChildByName( *boneIter );
204       if ( boneActor )
205       {
206         ConnectBoneActor( boneActor, boneIdx, boneCount );
207         boneIdx++;
208       }
209     }
210   }
211 }
212
213 void MeshAttachment::ConnectBoneActor( Internal::ActorPtr boneActor,
214                                        size_t             boneIdx,
215                                        size_t             boneCount )
216 {
217   Connector* connector = new Connector( boneActor, boneIdx, *this );
218   mConnectors.PushBack( connector );
219   connector->ConnectNode();
220 }
221
222 void MeshAttachment::OnStageConnection2()
223 {
224   // Ensure current materials are staged
225   const SceneGraph::MeshAttachment& sceneObject = *mSceneObject;
226
227   const SceneGraph::Material* materialSceneObject = NULL;
228   if ( mMesh.mCustomMaterial )
229   {
230     mMesh.mCustomMaterial->Connect();
231     materialSceneObject = mMesh.mCustomMaterial->GetSceneObject();
232   }
233   else if ( mMesh.mMaterial )
234   {
235     mMesh.mMaterial->Connect();
236     materialSceneObject = mMesh.mMaterial->GetSceneObject();
237   }
238   DALI_ASSERT_DEBUG( materialSceneObject );
239
240   // And that the scene object has a connection to each material
241   SetMaterialMessage( mStage->GetUpdateInterface(), sceneObject, materialSceneObject );
242
243   // Ensure all staged bones are reconnected
244   for(ConnectorList::Iterator iter=mConnectors.Begin(); iter != mConnectors.End(); ++iter)
245   {
246     Connector* connector = (*iter);
247     connector->ConnectNode();
248   }
249 }
250
251 void MeshAttachment::OnStageDisconnection2()
252 {
253   DisconnectMaterial();
254 }
255
256 const SceneGraph::RenderableAttachment& MeshAttachment::GetSceneObject() const
257 {
258   DALI_ASSERT_DEBUG( mSceneObject != NULL );
259   return *mSceneObject;
260 }
261
262 void MeshAttachment::SetBoneNode( SceneGraph::Node* node, size_t boneIdx )
263 {
264   size_t boneCount = mMesh.mBoneNames.size();
265
266   SetBoneNodeMessage( mStage->GetUpdateInterface(), *mSceneObject, node, boneIdx, boneCount );
267 }
268
269 // Helper class for connecting Nodes to the scene-graph MeshAttachment
270 MeshAttachment::Connector::Connector(
271   Internal::ActorPtr boneActor,
272   size_t             boneIdx,
273   MeshAttachment&    meshAttachment)
274 : mMeshAttachment(meshAttachment),
275   mActor(boneActor.Get()),
276   mBoneIdx(boneIdx)
277 {
278   if( mActor )
279   {
280     mActor->AddObserver( *this );
281     ConnectNode();
282   }
283 }
284
285 MeshAttachment::Connector::~Connector()
286 {
287   if( mActor)
288   {
289     mActor->RemoveObserver( *this );
290   }
291 }
292
293 void MeshAttachment::Connector::SceneObjectAdded( ProxyObject& proxy )
294 {
295   ConnectNode();
296 }
297
298 void MeshAttachment::Connector::SceneObjectRemoved( ProxyObject& proxy )
299 {
300   ConnectNode();
301 }
302
303 void MeshAttachment::Connector::ProxyDestroyed( ProxyObject& proxy )
304 {
305   mActor = NULL;
306
307   ConnectNode();
308 }
309
310 void MeshAttachment::Connector::ConnectNode()
311 {
312   SceneGraph::Node* theNode( NULL );
313
314   if( mActor != NULL )
315   {
316     const SceneGraph::PropertyOwner* object = mActor->GetSceneObject();
317     if ( NULL != object )
318     {
319       const SceneGraph::Node* aNode = dynamic_cast< const SceneGraph::Node* >( object );
320       if( aNode != NULL )
321       {
322         theNode = const_cast< SceneGraph::Node* >( aNode );
323       }
324     }
325   }
326
327   mMeshAttachment.SetBoneNode( theNode, mBoneIdx );
328 }
329
330
331 } // namespace Internal
332
333 } // namespace Dali