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