Refactored shader effect implementation.
[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 // EXTERNAL INCLUDES
22 #include <fstream>
23
24 // INTERNAL INCLUDES
25 #include <dali/public-api/math/vector2.h>
26 #include <dali/public-api/math/matrix.h>
27 #include <dali/public-api/math/matrix3.h>
28 #include <dali/public-api/shader-effects/shader-effect.h>
29 #include <dali/public-api/object/type-registry.h>
30 #include <dali/public-api/scripting/scripting.h>
31 #include "dali-shaders.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/update/common/animatable-property.h>
36 #include <dali/internal/update/manager/update-manager.h>
37 #include <dali/internal/event/common/stage-impl.h>
38 #include <dali/internal/event/common/thread-local-storage.h>
39 #include <dali/internal/render/shaders/shader.h>
40 #include <dali/internal/update/common/property-owner-messages.h>
41 #include <dali/internal/update/animation/scene-graph-constraint-base.h>
42
43 using Dali::Internal::SceneGraph::UpdateManager;
44 using Dali::Internal::SceneGraph::UniformMeta;
45 using Dali::Internal::SceneGraph::Shader;
46 using Dali::Internal::SceneGraph::AnimatableProperty;
47 using Dali::Internal::SceneGraph::PropertyBase;
48 using Dali::Internal::SceneGraph::PropertyBase;
49 using Dali::Internal::SceneGraph::RenderQueue;
50 using std::string;
51
52 namespace Dali
53 {
54
55 const Property::Index ShaderEffect::GRID_DENSITY        = 0;
56 const Property::Index ShaderEffect::IMAGE               = 1;
57 const Property::Index ShaderEffect::PROGRAM             = 2;
58 const Property::Index ShaderEffect::GEOMETRY_HINTS      = 3;
59
60 namespace Internal
61 {
62
63 ShaderEffect::DefaultPropertyLookup* ShaderEffect::mDefaultPropertyLookup = NULL;
64
65 namespace
66 {
67
68 struct WrapperStrings
69 {
70   const char* vertexShaderPrefix;
71   const char* fragmentShaderPrefix;
72   const char* vertexShaderPostfix;
73   const char* fragmentShaderPostfix;
74 };
75
76 WrapperStrings customShaderWrappers [] =
77 {
78   {
79     CustomImagePrefixVertex.c_str(), CustomImagePrefixFragment.c_str(),
80     CustomImagePostfixVertex.c_str(), CustomImagePostfixFragment.c_str()
81   },
82   {
83     CustomFontPrefixVertex.c_str(), CustomFontPrefixFragment.c_str(),
84     CustomFontPostfixVertex.c_str(), CustomFontPostfixFragment.c_str()
85   },
86   {
87     CustomMeshPrefixVertex.c_str(), CustomMeshPrefixFragment.c_str(),
88     MeshVertex.c_str(), MeshFragment.c_str()
89   }
90 };
91
92 BaseHandle Create()
93 {
94   Internal::ShaderEffectPtr internal = Internal::ShaderEffect::New( );
95
96   ShaderFactory::LoadTextSubtypeShaders(internal);
97
98   return Dali::ShaderEffect(internal.Get());
99 }
100
101 TypeRegistration mType( typeid(Dali::ShaderEffect), typeid(Dali::Handle), Create );
102
103 const std::string DEFAULT_PROPERTY_NAMES[] =
104 {
105   "grid-density",
106   "image",
107   "program",
108   "geometry-hints",
109 };
110 const int DEFAULT_PROPERTY_COUNT = sizeof( DEFAULT_PROPERTY_NAMES ) / sizeof( std::string );
111
112 const Property::Type DEFAULT_PROPERTY_TYPES[DEFAULT_PROPERTY_COUNT] =
113 {
114   Property::FLOAT,    // "grid-density",
115   Property::MAP,      // "image",
116   Property::MAP,      // "program",
117   Property::INTEGER,  // "geometry-hints",
118 };
119
120 std::string GetFileContents( const std::string& filename )
121 {
122   std::ifstream input( filename.c_str() );
123   return std::string( std::istreambuf_iterator<char>(input), std::istreambuf_iterator<char>() );
124 }
125
126 std::string GetShader(const std::string& field, const Property::Value& property)
127 {
128   if( property.HasKey(field) )
129   {
130     DALI_ASSERT_ALWAYS(property.GetValue(field).GetType() == Property::STRING && "Shader property is not a string" );
131
132     // we could also check here for an array of strings as convenience for json not having multi line strings
133     return property.GetValue(field).Get<std::string>();
134   }
135   else
136   {
137     // convention of shader field appended with -filename signifies a file
138     std::string filenameKey(std::string(field) + std::string("-filename"));
139
140     if( property.HasKey( filenameKey ) )
141     {
142       DALI_ASSERT_ALWAYS(property.GetValue(filenameKey).GetType() == Property::STRING && "Shader filename property is not a string" );
143       // this should eventually be done by an adaptor interface
144       return GetFileContents( property.GetValue(filenameKey).Get<std::string>() );
145     }
146   }
147
148   return std::string();
149 }
150
151 } // anon namespace
152
153
154 ShaderEffectPtr ShaderEffect::New( Dali::ShaderEffect::GeometryHints hints )
155 {
156   ThreadLocalStorage& tls = ThreadLocalStorage::Get();
157   UpdateManager& updateManager = tls.GetUpdateManager();
158   ShaderFactory& shaderFactory = tls.GetShaderFactory();
159
160   // Create a new scene-object, temporarily owned
161   Shader* sceneObject = new Shader( hints );
162   DALI_ASSERT_DEBUG( NULL != sceneObject );
163
164   ShaderEffectPtr shaderEffect( new ShaderEffect( updateManager, shaderFactory, *sceneObject ) );
165   shaderEffect->RegisterObject();
166
167   return shaderEffect;
168 }
169
170 ShaderEffectPtr ShaderEffect::New( const string& vertexShader,
171                                    const string& fragmentShader,
172                                    GeometryType geometryType,
173                                    Dali::ShaderEffect::GeometryHints hints )
174 {
175   return NewWithPrefix( "", vertexShader, "", fragmentShader, geometryType, hints);
176 }
177
178 ShaderEffectPtr ShaderEffect::NewWithPrefix( const string& vertexShaderPrefix,
179                                              const string& vertexShader,
180                                              const string& fragmentShaderPrefix,
181                                              const string& fragmentShader,
182                                              GeometryType geometryTypes,
183                                              Dali::ShaderEffect::GeometryHints hints )
184 {
185   ShaderEffectPtr shaderEffect( New(hints) );
186   ShaderFactory::LoadTextSubtypeShaders(shaderEffect);
187
188   shaderEffect->SetPrograms( geometryTypes, vertexShaderPrefix, vertexShader, fragmentShaderPrefix, fragmentShader );
189   return shaderEffect;
190 }
191
192 ShaderEffectPtr ShaderEffect::New( const string& imageVertexShader,
193                                    const string& imageFragmentShader,
194                                    const string& textVertexShader,
195                                    const string& textFragmentShader,
196                                    const string& texturedMeshVertexShader,
197                                    const string& texturedMeshFragmentShader,
198                                    const string& meshVertexShader,
199                                    const string& meshFragmentShader,
200                                    Dali::ShaderEffect::GeometryHints hints )
201 {
202   ShaderEffectPtr shaderEffect( New(hints) );
203
204   ShaderFactory::LoadTextSubtypeShaders(shaderEffect);
205
206   shaderEffect->SetWrappedProgram( GEOMETRY_TYPE_IMAGE, SHADER_SUBTYPE_ALL, "", "", imageVertexShader, imageFragmentShader );
207   shaderEffect->SetWrappedProgram( GEOMETRY_TYPE_TEXT, SHADER_DEFAULT, "", "", textVertexShader, textFragmentShader );
208   shaderEffect->SetWrappedProgram( GEOMETRY_TYPE_TEXTURED_MESH, SHADER_SUBTYPE_ALL, "", "", texturedMeshVertexShader, texturedMeshFragmentShader );
209   shaderEffect->SetWrappedProgram( GEOMETRY_TYPE_MESH, SHADER_SUBTYPE_ALL, "", "", meshVertexShader, meshFragmentShader );
210
211   return shaderEffect;
212 }
213
214 ShaderEffect::~ShaderEffect()
215 {
216   DALI_ASSERT_DEBUG( mSceneObject != NULL );
217
218   // Guard to allow handle destruction after Core has been destroyed
219   if ( Stage::IsInstalled() )
220   {
221     // Remove scene-object using a message to the UpdateManager
222     RemoveShaderMessage( mUpdateManager, *mSceneObject );
223
224     UnregisterObject();
225   }
226 }
227
228 ShaderEffect::ShaderEffect( UpdateManager& updateManager, ShaderFactory& shaderFactory, Shader& sceneObject )
229 : mUpdateManager( updateManager ),
230   mShaderFactory( shaderFactory ),
231   mSceneObject( &sceneObject ),
232   mConnectionCount (0)
233 {
234   // Transfer shader ownership to a scene message
235   AddShaderMessage( mUpdateManager, *mSceneObject );
236 }
237
238 void ShaderEffect::SetEffectImage( Dali::Image image )
239 {
240   // if images are the same, do nothing
241   if (mImage == image)
242   {
243     return;
244   }
245
246   if (mImage && mConnectionCount > 0)
247   {
248     // unset previous image
249     GetImplementation(mImage).Disconnect();
250   }
251
252   // in case image is empty this will reset our image handle
253   mImage = image;
254
255   if (!image)
256   {
257     // mSceneShader can be in a separate thread; queue a setter message
258     SetTextureIdMessage( mUpdateManager.GetEventToUpdate(), *mSceneObject, 0 );
259   }
260   else
261   {
262     // tell image that we're using it
263     if (mConnectionCount > 0)
264     {
265       GetImplementation(mImage).Connect();
266     }
267     // mSceneShader can be in a separate thread; queue a setter message
268     SetTextureIdMessage( mUpdateManager.GetEventToUpdate(), *mSceneObject, GetImplementation(mImage).GetResourceId() );
269   }
270 }
271
272 void ShaderEffect::SetUniform( const std::string& name, Property::Value value, UniformCoordinateType uniformCoordinateType )
273 {
274   // Register the property if it does not exist
275   Property::Index index = GetPropertyIndex( name );
276   if ( Property::INVALID_INDEX == index )
277   {
278     index = RegisterProperty( name, value );
279   }
280
281   SetProperty( index, value );
282
283   SetCoordinateTypeMessage( mUpdateManager.GetEventToUpdate(), *mCustomMetadata[index], uniformCoordinateType );
284 }
285
286 void ShaderEffect::AttachExtension( Dali::ShaderEffect::Extension *extension )
287 {
288   DALI_ASSERT_ALWAYS( extension != NULL && "Attaching uninitialized extension" );
289   mExtension = IntrusivePtr<Dali::ShaderEffect::Extension>( extension );
290 }
291
292 Dali::ShaderEffect::Extension& ShaderEffect::GetExtension()
293 {
294   DALI_ASSERT_ALWAYS( mExtension && "Getting uninitialized extension" );
295   return *mExtension;
296 }
297
298 const Dali::ShaderEffect::Extension& ShaderEffect::GetExtension() const
299 {
300   DALI_ASSERT_ALWAYS( mExtension && "Getting uninitialized extension" );
301   return *mExtension;
302 }
303
304 void ShaderEffect::SetProgram( GeometryType geometryType, ShaderSubTypes subType,
305                                const string& vertexSource, const string& fragmentSource,
306                                ShaderEffect::FixedVertexShader fixedShader )
307 {
308   SetProgramImpl(geometryType, subType, vertexSource, fragmentSource, fixedShader);
309 }
310
311 void ShaderEffect::SetProgram( GeometryType geometryType, ShaderSubTypes subType,
312                                const std::string& vertexPrefix, const std::string& fragmentPrefix,
313                                const std::string& vertexSource, const std::string& fragmentSource,
314                                ShaderEffect::FixedVertexShader fixedShader )
315 {
316   const std::string vertex( vertexPrefix + vertexSource );
317   const std::string fragment( fragmentPrefix + fragmentSource );
318   SetProgramImpl( geometryType, subType, vertex, fragment, fixedShader );
319 }
320
321 void ShaderEffect::Connect()
322 {
323   ++mConnectionCount;
324
325   if (mImage && mConnectionCount == 1)
326   {
327     GetImplementation(mImage).Connect();
328
329     // Image may have changed resource due to load/release policy. Ensure correct texture ID is set on scene graph object
330     SetTextureIdMessage( mUpdateManager.GetEventToUpdate(), *mSceneObject, GetImplementation(mImage).GetResourceId() );
331   }
332 }
333
334 void ShaderEffect::Disconnect()
335 {
336   DALI_ASSERT_DEBUG(mConnectionCount > 0);
337   --mConnectionCount;
338
339   if (mImage && mConnectionCount == 0)
340   {
341      GetImplementation(mImage).Disconnect();
342   }
343 }
344
345 bool ShaderEffect::IsSceneObjectRemovable() const
346 {
347   return false; // The Shader is not removed during this proxy's lifetime
348 }
349
350 unsigned int ShaderEffect::GetDefaultPropertyCount() const
351 {
352   return DEFAULT_PROPERTY_COUNT;
353 }
354
355 void ShaderEffect::GetDefaultPropertyIndices( Property::IndexContainer& indices ) const
356 {
357   indices.reserve( DEFAULT_PROPERTY_COUNT );
358
359   for ( int i = 0; i < DEFAULT_PROPERTY_COUNT; ++i )
360   {
361     indices.push_back( i );
362   }
363 }
364
365 const std::string& ShaderEffect::GetDefaultPropertyName(Property::Index index) const
366 {
367   if( index < DEFAULT_PROPERTY_COUNT )
368   {
369     return DEFAULT_PROPERTY_NAMES[index];
370   }
371   else
372   {
373     // index out of range..return empty string
374     static const std::string INVALID_PROPERTY_NAME;
375     return INVALID_PROPERTY_NAME;
376   }
377 }
378
379 Property::Index ShaderEffect::GetDefaultPropertyIndex(const std::string& name) const
380 {
381   Property::Index index = Property::INVALID_INDEX;
382
383   // Lazy initialization of static mDefaultPropertyLookup
384   if (!mDefaultPropertyLookup)
385   {
386     mDefaultPropertyLookup = new DefaultPropertyLookup();
387
388     for (int i=0; i<DEFAULT_PROPERTY_COUNT; ++i)
389     {
390       (*mDefaultPropertyLookup)[DEFAULT_PROPERTY_NAMES[i]] = i;
391     }
392   }
393   DALI_ASSERT_DEBUG( NULL != mDefaultPropertyLookup );
394
395   // Look for name in default properties
396   DefaultPropertyLookup::const_iterator result = mDefaultPropertyLookup->find( name );
397   if ( mDefaultPropertyLookup->end() != result )
398   {
399     index = result->second;
400   }
401
402   return index;
403 }
404
405 bool ShaderEffect::IsDefaultPropertyWritable(Property::Index index) const
406 {
407   return true;
408 }
409
410 bool ShaderEffect::IsDefaultPropertyAnimatable(Property::Index index) const
411 {
412   return false;
413 }
414
415 bool ShaderEffect::IsDefaultPropertyAConstraintInput( Property::Index index ) const
416 {
417   return false;
418 }
419
420 Property::Type ShaderEffect::GetDefaultPropertyType(Property::Index index) const
421 {
422   if( index < DEFAULT_PROPERTY_COUNT )
423   {
424     return DEFAULT_PROPERTY_TYPES[index];
425   }
426   else
427   {
428     // index out of range...return Property::NONE
429     return Property::NONE;
430   }
431 }
432
433 void ShaderEffect::SetDefaultProperty( Property::Index index, const Property::Value& propertyValue )
434 {
435   switch ( index )
436   {
437     case Dali::ShaderEffect::GRID_DENSITY:
438     {
439       SetGridDensityMessage( mUpdateManager.GetEventToUpdate(), *mSceneObject, propertyValue.Get<float>() );
440       break;
441     }
442
443     case Dali::ShaderEffect::IMAGE:
444     {
445       Dali::Image img(Scripting::NewImage( propertyValue ));
446       if(img)
447       {
448         SetEffectImage( img );
449       }
450       else
451       {
452         DALI_LOG_WARNING("Cannot create image from property value for ShaderEffect image\n");
453       }
454       break;
455     }
456
457     case Dali::ShaderEffect::PROGRAM:
458     {
459       std::string vertexPrefix   = GetShader("vertex-prefix", propertyValue);
460       std::string fragmentPrefix = GetShader("fragment-prefix", propertyValue);
461       std::string vertex         = GetShader("vertex", propertyValue);
462       std::string fragment       = GetShader("fragment", propertyValue);
463
464       GeometryType geometryType      = GEOMETRY_TYPE_IMAGE;
465
466       if( propertyValue.HasKey("geometry-type") )
467       {
468         Property::Value geometryValue  = propertyValue.GetValue("geometry-type");
469         DALI_ASSERT_ALWAYS(geometryValue.GetType() == Property::STRING && "Geometry type is not a string" );
470
471         std::string s = geometryValue.Get<std::string>();
472         if(s == "GEOMETRY_TYPE_IMAGE")
473         {
474           geometryType  = GEOMETRY_TYPE_IMAGE;
475         }
476         else if (s == "GEOMETRY_TYPE_TEXT")
477         {
478           geometryType  = GEOMETRY_TYPE_TEXT;
479         }
480         else if( s == "GEOMETRY_TYPE_MESH")
481         {
482           geometryType  = GEOMETRY_TYPE_MESH;
483         }
484         else if( s == "GEOMETRY_TYPE_TEXTURED_MESH")
485         {
486           geometryType  = GEOMETRY_TYPE_TEXTURED_MESH;
487         }
488         else
489         {
490           DALI_ASSERT_ALWAYS(!"Geometry type unknown" );
491         }
492       }
493       SetPrograms( geometryType, vertexPrefix, vertex, fragmentPrefix, fragment );
494       break;
495     }
496
497     case Dali::ShaderEffect::GEOMETRY_HINTS:
498     {
499       Dali::ShaderEffect::GeometryHints hint = Dali::ShaderEffect::HINT_NONE;
500       Property::Value geometryHintsValue   = propertyValue.GetValue("geometry-hints");
501
502       std::string s = geometryHintsValue.Get<std::string>();
503       if(s == "HINT_NONE")
504       {
505         hint = Dali::ShaderEffect::HINT_NONE;
506       }
507       else if(s == "HINT_GRID_X")
508       {
509         hint = Dali::ShaderEffect::HINT_GRID_X;
510       }
511       else if(s == "HINT_GRID_Y")
512       {
513         hint = Dali::ShaderEffect::HINT_GRID_Y;
514       }
515       else if(s == "HINT_GRID")
516       {
517         hint = Dali::ShaderEffect::HINT_GRID;
518       }
519       else if(s == "HINT_DEPTH_BUFFER")
520       {
521         hint = Dali::ShaderEffect::HINT_DEPTH_BUFFER;
522       }
523       else if(s == "HINT_BLENDING")
524       {
525         hint = Dali::ShaderEffect::HINT_BLENDING;
526       }
527       else
528       {
529         DALI_ASSERT_ALWAYS(!"Geometry hint unknown" );
530       }
531
532       SetHintsMessage( mUpdateManager.GetEventToUpdate(), *mSceneObject, hint );
533
534       break;
535     }
536
537     default:
538     {
539       DALI_ASSERT_ALWAYS(false && "ShaderEffect property enumeration out of range"); // should not come here
540       break;
541     }
542   }
543 }
544
545 Property::Value ShaderEffect::GetDefaultProperty(Property::Index /*index*/) const
546 {
547   // none of our properties are readable so return empty
548   return Property::Value();
549 }
550
551 void ShaderEffect::InstallSceneObjectProperty( PropertyBase& newProperty, const std::string& name, unsigned int index )
552 {
553   // Warning - the property is added to the Shader object in the Update thread and the meta-data is added in the Render thread (through a secondary message)
554
555   // mSceneObject is being used in a separate thread; queue a message to add the property
556   InstallCustomPropertyMessage( mUpdateManager.GetEventToUpdate(), *mSceneObject, newProperty ); // Message takes ownership
557
558   // mSceneObject requires metadata for each custom property (uniform)
559   UniformMeta* meta = UniformMeta::New( name, newProperty, Dali::ShaderEffect::COORDINATE_TYPE_DEFAULT );
560   // mSceneObject is being used in a separate thread; queue a message to add the property
561   InstallUniformMetaMessage( mUpdateManager.GetEventToUpdate(), *mSceneObject, *meta ); // Message takes ownership
562
563   // Add entry to the metadata lookup
564   mCustomMetadata[index] = meta;
565 }
566
567 const SceneGraph::PropertyOwner* ShaderEffect::GetSceneObject() const
568 {
569   return mSceneObject;
570 }
571
572 const PropertyBase* ShaderEffect::GetSceneObjectAnimatableProperty( Property::Index index ) const
573 {
574   CustomPropertyLookup::const_iterator entry = GetCustomPropertyLookup().find( index );
575
576   DALI_ASSERT_ALWAYS( GetCustomPropertyLookup().end() != entry && "Property index is invalid" );
577
578   DALI_ASSERT_ALWAYS( entry->second.IsAnimatable() && "shader effect has only animatable properties" );
579
580   return dynamic_cast<const PropertyBase*>( entry->second.GetSceneGraphProperty() );
581 }
582
583 const PropertyInputImpl* ShaderEffect::GetSceneObjectInputProperty( Property::Index index ) const
584 {
585   CustomPropertyLookup::const_iterator entry = GetCustomPropertyLookup().find( index );
586
587   DALI_ASSERT_ALWAYS( GetCustomPropertyLookup().end() != entry && "Property index is invalid" );
588
589   DALI_ASSERT_ALWAYS( entry->second.IsAnimatable() && "shader effect has only animatable properties" );
590
591   return entry->second.GetSceneGraphProperty();
592 }
593
594 void ShaderEffect::SetPrograms( GeometryType  geometryTypes,
595                                 const std::string& vertexShaderPrefix,
596                                 const std::string& vertexShader,
597                                 const std::string& fragmentShaderPrefix,
598                                 const std::string& fragmentShader )
599 {
600   static std::string emptyStr;
601
602   if( geometryTypes & GEOMETRY_TYPE_IMAGE )
603   {
604     SetWrappedProgram( GEOMETRY_TYPE_IMAGE, SHADER_SUBTYPE_ALL, vertexShaderPrefix, fragmentShaderPrefix, vertexShader, fragmentShader );
605   }
606   else
607   {
608     SetWrappedProgram( GEOMETRY_TYPE_IMAGE, SHADER_SUBTYPE_ALL, emptyStr, emptyStr, emptyStr, emptyStr );
609   }
610
611   if( geometryTypes & GEOMETRY_TYPE_TEXT )
612   {
613     // Only change the default program, leaving the other sub-types as-is.
614     SetWrappedProgram( GEOMETRY_TYPE_TEXT, SHADER_DEFAULT, vertexShaderPrefix, fragmentShaderPrefix, vertexShader, fragmentShader );
615   }
616   else
617   {
618     SetWrappedProgram( GEOMETRY_TYPE_TEXT, SHADER_DEFAULT, emptyStr, emptyStr, emptyStr, emptyStr );
619   }
620
621   if( geometryTypes & GEOMETRY_TYPE_TEXTURED_MESH )
622   {
623     SetWrappedProgram( GEOMETRY_TYPE_TEXTURED_MESH, SHADER_SUBTYPE_ALL, vertexShaderPrefix, fragmentShaderPrefix, vertexShader, fragmentShader );
624   }
625   else
626   {
627     SetWrappedProgram( GEOMETRY_TYPE_TEXTURED_MESH, SHADER_SUBTYPE_ALL, emptyStr, emptyStr, emptyStr, emptyStr );
628   }
629
630   if( geometryTypes & GEOMETRY_TYPE_MESH )
631   {
632     SetWrappedProgram( GEOMETRY_TYPE_MESH, SHADER_SUBTYPE_ALL, vertexShaderPrefix, fragmentShaderPrefix, vertexShader, fragmentShader );
633   }
634   else
635   {
636     SetWrappedProgram( GEOMETRY_TYPE_MESH, SHADER_SUBTYPE_ALL, emptyStr, emptyStr, emptyStr, emptyStr );
637   }
638 }
639
640 void ShaderEffect::SetWrappedProgram( GeometryType geometryType, ShaderSubTypes subType,
641                                       const string& vertexPrefix, const string& fragmentPrefix,
642                                       const string& vertexSnippet, const string& fragmentSnippet )
643 {
644   // create complete shader program strings for the given geometry type
645   unsigned int index = 0;
646   switch( geometryType )
647   {
648     case GEOMETRY_TYPE_IMAGE:
649     {
650       index = 0;
651       break;
652     }
653     case GEOMETRY_TYPE_TEXT:
654     {
655       index = 1;
656       break;
657     }
658     case GEOMETRY_TYPE_MESH:
659     case GEOMETRY_TYPE_TEXTURED_MESH:
660     {
661       index = 2;
662       break;
663     }
664     case GEOMETRY_TYPE_LAST:
665     {
666       DALI_ASSERT_DEBUG(0 && "Wrong geometry type");
667       break;
668     }
669   }
670
671   string vertexSource = vertexPrefix + customShaderWrappers[index].vertexShaderPrefix;
672   string fragmentSource = fragmentPrefix + customShaderWrappers[index].fragmentShaderPrefix;
673
674   // Append the custom vertex shader code if supplied, otherwise append the default
675   if ( vertexSnippet.length() > 0 )
676   {
677     vertexSource.append( vertexSnippet );
678   }
679   else
680   {
681     vertexSource.append( customShaderWrappers[index].vertexShaderPostfix );
682   }
683
684   // Append the custom fragment shader code if supplied, otherwise append the default
685   if ( fragmentSnippet.length() > 0 )
686   {
687     fragmentSource.append( fragmentSnippet );
688   }
689   else
690   {
691     fragmentSource.append( customShaderWrappers[index].fragmentShaderPostfix );
692   }
693
694   // Add the program
695   SetProgramImpl( geometryType, subType, vertexSource, fragmentSource, ShaderEffect::FLEXIBLE );
696 }
697
698 void ShaderEffect::SetProgramImpl( GeometryType geometryType, ShaderSubTypes subType,
699                                    const string& vertexSource, const string& fragmentSource,
700                                    ShaderEffect::FixedVertexShader fixedShader )
701 {
702   // Load done asynchronously in update thread. SetProgram message below must be processed afterwards.
703   // Therefore, resource manager cannot farm out the loading to the adaptor resource threads,
704   // but must instead use synchronous loading via PlatformAbstraction::LoadFile()
705   size_t shaderHash;
706   ResourceTicketPtr ticket( mShaderFactory.Load(vertexSource, fragmentSource, shaderHash) );
707
708   DALI_LOG_INFO( Debug::Filter::gShader, Debug::General, "ShaderEffect: SetProgram(geometryType %d subType:%d ticket.id:%d)\n", geometryType, subType, ticket->GetId() );
709
710   bool areVerticesFixed = (fixedShader == ShaderEffect::FIXED);
711
712   // Add shader program to scene-object using a message to the UpdateManager
713   SetShaderProgramMessage( mUpdateManager, *mSceneObject, geometryType, subType, ticket->GetId(), shaderHash, areVerticesFixed );
714
715   mTickets.push_back(ticket);       // add ticket to collection to keep it alive.
716 }
717
718
719 } // namespace Internal
720
721 } // namespace Dali