Changed ImageActor and to use new renderers and removed ImageAttachement.
[platform/core/uifw/dali-core.git] / dali / internal / event / effects / shader-effect-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/effects/shader-effect-impl.h>
20
21 // INTERNAL INCLUDES
22 #include <dali/public-api/math/matrix.h>
23 #include <dali/public-api/math/matrix3.h>
24 #include <dali/public-api/math/vector2.h>
25 #include <dali/public-api/object/type-registry.h>
26 #include <dali/devel-api/scripting/scripting.h>
27 #include <dali/public-api/shader-effects/shader-effect.h>
28 #include <dali/internal/event/actors/image-actor-impl.h>
29 #include <dali/internal/event/common/property-helper.h>
30 #include <dali/internal/event/common/stage-impl.h>
31 #include <dali/internal/event/common/thread-local-storage.h>
32 #include <dali/internal/event/effects/shader-declarations.h>
33 #include <dali/internal/event/effects/shader-factory.h>
34 #include <dali/internal/event/images/image-impl.h>
35 #include <dali/internal/render/shaders/scene-graph-shader.h>
36 #include <dali/internal/render/shaders/uniform-meta.h>
37 #include <dali/internal/update/animation/scene-graph-constraint-base.h>
38 #include <dali/internal/update/common/animatable-property.h>
39 #include <dali/internal/update/manager/update-manager.h>
40 #include "dali-shaders.h"
41
42 using Dali::Internal::SceneGraph::UpdateManager;
43 using Dali::Internal::SceneGraph::UniformMeta;
44 using Dali::Internal::SceneGraph::Shader;
45 using Dali::Internal::SceneGraph::AnimatableProperty;
46 using Dali::Internal::SceneGraph::PropertyBase;
47 using Dali::Internal::SceneGraph::RenderQueue;
48 using std::string;
49
50 namespace Dali
51 {
52
53 namespace Internal
54 {
55
56 namespace
57 {
58
59 // Properties
60
61 //              Name             Type   writable animatable constraint-input  enum for index-checking
62 DALI_PROPERTY_TABLE_BEGIN
63 DALI_PROPERTY( "gridDensity",    FLOAT,   true,    false,   false,   Dali::ShaderEffect::Property::GRID_DENSITY   )
64 DALI_PROPERTY( "image",          MAP,     true,    false,   false,   Dali::ShaderEffect::Property::IMAGE          )
65 DALI_PROPERTY( "program",        MAP,     true,    false,   false,   Dali::ShaderEffect::Property::PROGRAM        )
66 DALI_PROPERTY( "geometryHints",  STRING,  true,    false,   false,   Dali::ShaderEffect::Property::GEOMETRY_HINTS )
67 DALI_PROPERTY_TABLE_END( DEFAULT_ACTOR_PROPERTY_START_INDEX )
68
69 BaseHandle Create()
70 {
71   Internal::ShaderEffectPtr internal = Internal::ShaderEffect::New();
72
73   return Dali::ShaderEffect(internal.Get());
74 }
75
76 TypeRegistration mType( typeid(Dali::ShaderEffect), typeid(Dali::Handle), Create );
77
78 struct WrapperStrings
79 {
80   const char* vertexShaderPrefix;
81   const char* fragmentShaderPrefix;
82   const char* vertexShaderPostfix;
83   const char* fragmentShaderPostfix;
84 };
85
86 WrapperStrings customImageShaderWrappers =
87 {
88   CustomImagePrefixVertex, CustomImagePrefixFragment,
89   CustomImagePostfixVertex, CustomImagePostfixFragment
90 };
91
92 /**
93  * Helper to wrap the program with our default pre and postfix if needed
94  * @param[in] vertexPrefix from application
95  * @param[in] vertexBody from application
96  */
97 std::string WrapVertexShader( const std::string& vertexPrefix, const std::string& vertexBody )
98 {
99   std::string vertexSource = vertexPrefix + customImageShaderWrappers.vertexShaderPrefix;
100
101   // Append the custom vertex shader code if supplied, otherwise append the default
102   if ( vertexBody.length() > 0 )
103   {
104     vertexSource.append( vertexBody );
105   }
106   else
107   {
108     vertexSource.append( customImageShaderWrappers.vertexShaderPostfix );
109   }
110
111   return vertexSource;
112 }
113
114 /**
115  * Helper to wrap the program with our default pre and postfix if needed
116  * @param[in] fragmentPrefix from application
117  * @param[in] fragmentBody from application
118  */
119 std::string WrapFragmentShader( const std::string& fragmentPrefix, const std::string& fragmentBody )
120 {
121   std::string fragmentSource = fragmentPrefix + customImageShaderWrappers.fragmentShaderPrefix;
122
123   // Append the custom fragment shader code if supplied, otherwise append the default
124   if ( fragmentBody.length() > 0 )
125   {
126     fragmentSource.append( fragmentBody );
127   }
128   else
129   {
130     fragmentSource.append( customImageShaderWrappers.fragmentShaderPostfix );
131   }
132
133   return fragmentSource;
134 }
135
136 std::string GetShader(const std::string& field, const Property::Value& property)
137 {
138   std::string retval;
139   const Property::Map* map = property.GetMap();
140   if( map )
141   {
142     const Property::Value* value = map->Find( field );
143     if( value )
144     {
145       value->Get( retval );
146     }
147   }
148
149   return retval;
150 }
151
152 } // unnamed namespace
153
154 ShaderEffectPtr ShaderEffect::New( Dali::ShaderEffect::GeometryHints hints )
155 {
156   Stage* stage = Stage::GetCurrent();
157
158   if( stage )
159   {
160     ShaderEffectPtr shaderEffect( new ShaderEffect( *stage, hints ) );
161     shaderEffect->RegisterObject();
162     return shaderEffect;
163   }
164   else
165   {
166     return NULL;
167   }
168 }
169
170 ShaderEffect::ShaderEffect( EventThreadServices& eventThreadServices, Dali::ShaderEffect::GeometryHints hints )
171 : mEventThreadServices( eventThreadServices ),
172   mGeometryHints( hints ),
173   mGridDensity( Dali::ShaderEffect::DEFAULT_GRID_DENSITY )
174 {
175   mSceneObject = new SceneGraph::Shader( hints );
176   DALI_ASSERT_DEBUG( NULL != mSceneObject );
177
178   // Transfer shader ownership to a scene message
179   AddShaderMessage( eventThreadServices.GetUpdateManager(), *mSceneObject );
180 }
181
182 ShaderEffect::~ShaderEffect()
183 {
184   // Guard to allow handle destruction after Core has been destroyed
185   if ( Stage::IsInstalled() )
186   {
187     // Remove scene-object using a message to the UpdateManager
188     if( mSceneObject )
189     {
190       RemoveShaderMessage( mEventThreadServices.GetUpdateManager(), *mSceneObject );
191     }
192     UnregisterObject();
193   }
194 }
195
196 void ShaderEffect::SetEffectImage( Dali::Image image )
197 {
198   // if images are the same, do nothing
199   if ( mEffectImage == image )
200   {
201     return;
202   }
203
204   if ( mEffectImage && mConnectedActors.size() > 0 )
205   {
206     // unset previous image
207     GetImplementation( mEffectImage ).Disconnect();
208   }
209
210   // in case image is empty this will reset our image handle
211   mEffectImage = image;
212
213   if( image )
214   {
215     // tell image that we're using it
216     if (mConnectedActors.size() > 0)
217     {
218       GetImplementation( mEffectImage ).Connect();
219     }
220   }
221
222   //inform connected actors the image has been unset
223   for(std::vector< ActorPtr >::iterator it = mConnectedActors.begin(); it != mConnectedActors.end(); ++it )
224   {
225     ImageActor* imageActor = dynamic_cast< ImageActor* >( it->Get() );
226     if( imageActor )
227     {
228       imageActor->EffectImageUpdated();
229     }
230   }
231 }
232
233 void ShaderEffect::SetUniform( const std::string& name, Property::Value value, UniformCoordinateType uniformCoordinateType )
234 {
235   // Register the property if it does not exist
236   Property::Index index = RegisterProperty( name, value );
237
238   Uniform uniform = { name, index, value };
239   mUniforms.push_back( uniform );
240
241   //inform any connected actors
242   for(std::vector< ActorPtr >::iterator it = mConnectedActors.begin(); it != mConnectedActors.end(); ++it)
243   {
244     ImageActor* imageActor = dynamic_cast< ImageActor* >( (*it).Get() );
245     if( imageActor )
246     {
247       imageActor->EffectUniformUpdated( uniform );
248     }
249   }
250 }
251
252 void ShaderEffect::SetPrograms( const string& vertexSource, const string& fragmentSource )
253 {
254   SetPrograms( "", "", vertexSource, fragmentSource );
255 }
256
257 void ShaderEffect::SetPrograms( const std::string& vertexPrefix, const std::string& fragmentPrefix,
258                                 const std::string& vertexSource, const std::string& fragmentSource )
259 {
260   mVertexSource = WrapVertexShader( vertexPrefix, vertexSource );
261   mFragmentSource = WrapFragmentShader( fragmentPrefix, fragmentSource );
262 }
263
264 void ShaderEffect::Connect( ActorPtr actor )
265 {
266   if( !actor )
267   {
268     return;
269   }
270
271   std::vector< ActorPtr >::const_iterator it = std::find( mConnectedActors.begin(), mConnectedActors.end(), actor );
272   if( it == mConnectedActors.end() )
273   {
274     mConnectedActors.push_back( actor );
275   }
276
277   if( mEffectImage && mConnectedActors.size() == 1 )
278   {
279     GetImplementation( mEffectImage ).Connect();
280   }
281 }
282 void ShaderEffect::Disconnect( ActorPtr actor )
283 {
284   if( !actor )
285   {
286     return;
287   }
288
289   DALI_ASSERT_DEBUG(mConnectedActors.size() > 0);
290   std::vector< ActorPtr >::iterator match( std::remove( mConnectedActors.begin(), mConnectedActors.end(), actor ) );
291   mConnectedActors.erase( match, mConnectedActors.end() );
292
293   if (mEffectImage && mConnectedActors.size() == 0)
294   {
295      GetImplementation(mEffectImage).Disconnect();
296   }
297 }
298
299 unsigned int ShaderEffect::GetDefaultPropertyCount() const
300 {
301   return DEFAULT_PROPERTY_COUNT;
302 }
303
304 void ShaderEffect::GetDefaultPropertyIndices( Property::IndexContainer& indices ) const
305 {
306   indices.Reserve( DEFAULT_PROPERTY_COUNT );
307
308   for ( int i = 0; i < DEFAULT_PROPERTY_COUNT; ++i )
309   {
310     indices.PushBack( i );
311   }
312 }
313
314 const char* ShaderEffect::GetDefaultPropertyName(Property::Index index) const
315 {
316   if( index < DEFAULT_PROPERTY_COUNT )
317   {
318     return DEFAULT_PROPERTY_DETAILS[index].name;
319   }
320
321   return NULL;
322 }
323
324 Property::Index ShaderEffect::GetDefaultPropertyIndex(const std::string& name) const
325 {
326   Property::Index index = Property::INVALID_INDEX;
327
328   // Look for name in default properties
329   for( int i = 0; i < DEFAULT_PROPERTY_COUNT; ++i )
330   {
331     const Internal::PropertyDetails* property = &DEFAULT_PROPERTY_DETAILS[ i ];
332     if( 0 == strcmp( name.c_str(), property->name ) ) // dont want to convert rhs to string
333     {
334       index = i;
335       break;
336     }
337   }
338
339   return index;
340 }
341
342 bool ShaderEffect::IsDefaultPropertyWritable(Property::Index index) const
343 {
344   return DEFAULT_PROPERTY_DETAILS[ index ].writable;
345 }
346
347 bool ShaderEffect::IsDefaultPropertyAnimatable(Property::Index index) const
348 {
349   return DEFAULT_PROPERTY_DETAILS[ index ].animatable;
350 }
351
352 bool ShaderEffect::IsDefaultPropertyAConstraintInput( Property::Index index ) const
353 {
354   return DEFAULT_PROPERTY_DETAILS[ index ].constraintInput;
355 }
356
357 Property::Type ShaderEffect::GetDefaultPropertyType(Property::Index index) const
358 {
359   if( index < DEFAULT_PROPERTY_COUNT )
360   {
361     return DEFAULT_PROPERTY_DETAILS[index].type;
362   }
363
364   // index out of range...return Property::NONE
365   return Property::NONE;
366 }
367
368 void ShaderEffect::SetDefaultProperty( Property::Index index, const Property::Value& propertyValue )
369 {
370   switch ( index )
371   {
372     case Dali::ShaderEffect::Property::GRID_DENSITY:
373     {
374       propertyValue.Get( mGridDensity );
375       if( ( mGeometryHints & Dali::ShaderEffect::HINT_GRID_X ) ||
376           ( mGeometryHints & Dali::ShaderEffect::HINT_GRID_Y ) )
377       {
378         //inform all the connected actors
379         for(std::vector< ActorPtr >::iterator it = mConnectedActors.begin(); it != mConnectedActors.end(); ++it )
380         {
381           (*it)->RelayoutRequest();
382         }
383       }
384       break;
385     }
386
387     case Dali::ShaderEffect::Property::IMAGE:
388     {
389       Dali::Image img(Scripting::NewImage( propertyValue ));
390       if(img)
391       {
392         SetEffectImage( img );
393       }
394       else
395       {
396         DALI_LOG_WARNING("Cannot create image from property value for ShaderEffect image\n");
397       }
398       break;
399     }
400
401     case Dali::ShaderEffect::Property::PROGRAM:
402     {
403       std::string vertexPrefix   = GetShader("vertexPrefix",  propertyValue);
404       std::string fragmentPrefix = GetShader("fragmentPrefix",  propertyValue);
405       std::string vertex         = GetShader("vertex", propertyValue);
406       std::string fragment       = GetShader("fragment", propertyValue);
407
408       SetPrograms( vertexPrefix, fragmentPrefix, vertex, fragment );
409       break;
410     }
411
412     case Dali::ShaderEffect::Property::GEOMETRY_HINTS:
413     {
414       mGeometryHints = Dali::ShaderEffect::HINT_NONE;
415       std::string s = propertyValue.Get<std::string>();
416       if(s == "HINT_NONE")
417       {
418         mGeometryHints = Dali::ShaderEffect::HINT_NONE;
419       }
420       else if(s == "HINT_GRID_X")
421       {
422         mGeometryHints = Dali::ShaderEffect::HINT_GRID_X;
423       }
424       else if(s == "HINT_GRID_Y")
425       {
426         mGeometryHints = Dali::ShaderEffect::HINT_GRID_Y;
427       }
428       else if(s == "HINT_GRID")
429       {
430         mGeometryHints = Dali::ShaderEffect::HINT_GRID;
431       }
432       else if(s == "HINT_DEPTH_BUFFER")
433       {
434         mGeometryHints = Dali::ShaderEffect::HINT_DEPTH_BUFFER;
435       }
436       else if(s == "HINT_BLENDING")
437       {
438         mGeometryHints = Dali::ShaderEffect::HINT_BLENDING;
439       }
440       else if(s == "HINT_DOESNT_MODIFY_GEOMETRY")
441       {
442         mGeometryHints = Dali::ShaderEffect::HINT_DOESNT_MODIFY_GEOMETRY;
443       }
444       else
445       {
446         DALI_ASSERT_ALWAYS(!"Geometry hint unknown" );
447       }
448       break;
449     }
450
451     default:
452     {
453       // nothing to do
454       break;
455     }
456   }
457 }
458
459 Property::Value ShaderEffect::GetDefaultProperty(Property::Index /*index*/) const
460 {
461   // none of our properties are readable so return empty
462   return Property::Value();
463 }
464
465 const SceneGraph::PropertyOwner* ShaderEffect::GetSceneObject() const
466 {
467   return mSceneObject;
468 }
469
470 const PropertyBase* ShaderEffect::GetSceneObjectAnimatableProperty( Property::Index index ) const
471 {
472   PropertyMetadata* property = index >= PROPERTY_CUSTOM_START_INDEX ? static_cast<PropertyMetadata*>(FindCustomProperty( index )) : static_cast<PropertyMetadata*>(FindAnimatableProperty( index ));
473   DALI_ASSERT_ALWAYS( property && "Property index is invalid" );
474   return property->GetSceneGraphProperty();
475 }
476
477 const PropertyInputImpl* ShaderEffect::GetSceneObjectInputProperty( Property::Index index ) const
478 {
479   return GetSceneObjectAnimatableProperty( index );
480 }
481
482 } // namespace Internal
483
484 } // namespace Dali