Conversion to Apache 2.0 license
[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 {
459   // Load done asynchronously in update thread. SetProgram message below must be processed afterwards.
460   // Therefore, resource manager cannot farm out the loading to the adaptor resource threads,
461   // but must instead use synchronous loading via PlatformAbstraction::LoadFile()
462   size_t shaderHash;
463   ResourceTicketPtr ticket( mShaderFactory.Load(vertexSource, fragmentSource, shaderHash) );
464
465   DALI_LOG_INFO( Debug::Filter::gShader, Debug::General, "ShaderEffect: SetProgram(geometryType %d subType:%d ticket.id:%d)\n", geometryType, subType, ticket->GetId() );
466
467   // Add shader program to scene-object using a message to the UpdateManager
468   SetShaderProgramMessage( mUpdateManager, *mSceneObject, geometryType, subType, ticket->GetId(), shaderHash );
469
470   mTickets.push_back(ticket);       // add ticket to collection to keep it alive.
471 }
472
473
474 void ShaderEffect::SetProgram( GeometryType geometryType, ShaderSubTypes subType,
475                                const std::string& vertexPrefix, const std::string& fragmentPrefix,
476                                const std::string& vertexSource, const std::string& fragmentSource )
477 {
478   const std::string vertex( vertexPrefix + vertexSource );
479   const std::string fragment( fragmentPrefix + fragmentSource );
480   SetProgram( geometryType, subType, vertex, fragment );
481 }
482
483 void ShaderEffect::Connect()
484 {
485   ++mConnectionCount;
486
487   if (mImage && mConnectionCount == 1)
488   {
489     GetImplementation(mImage).Connect();
490
491     // Image may have changed resource due to load/release policy. Ensure correct texture ID is set on scene graph object
492     SetTextureIdMessage( mUpdateManager.GetEventToUpdate(), *mSceneObject, GetImplementation(mImage).GetResourceId() );
493   }
494 }
495
496 void ShaderEffect::Disconnect()
497 {
498   DALI_ASSERT_DEBUG(mConnectionCount > 0);
499   --mConnectionCount;
500
501   if (mImage && mConnectionCount == 0)
502   {
503      GetImplementation(mImage).Disconnect();
504   }
505 }
506
507 bool ShaderEffect::IsSceneObjectRemovable() const
508 {
509   return false; // The Shader is not removed during this proxy's lifetime
510 }
511
512 unsigned int ShaderEffect::GetDefaultPropertyCount() const
513 {
514   return DEFAULT_PROPERTY_COUNT;
515 }
516
517 void ShaderEffect::GetDefaultPropertyIndices( Property::IndexContainer& indices ) const
518 {
519   indices.reserve( DEFAULT_PROPERTY_COUNT );
520
521   for ( int i = 0; i < DEFAULT_PROPERTY_COUNT; ++i )
522   {
523     indices.push_back( i );
524   }
525 }
526
527 const std::string& ShaderEffect::GetDefaultPropertyName(Property::Index index) const
528 {
529   if( index < DEFAULT_PROPERTY_COUNT )
530   {
531     return DEFAULT_PROPERTY_NAMES[index];
532   }
533   else
534   {
535     // index out of range..return empty string
536     static const std::string INVALID_PROPERTY_NAME;
537     return INVALID_PROPERTY_NAME;
538   }
539 }
540
541 Property::Index ShaderEffect::GetDefaultPropertyIndex(const std::string& name) const
542 {
543   Property::Index index = Property::INVALID_INDEX;
544
545   // Lazy initialization of static mDefaultPropertyLookup
546   if (!mDefaultPropertyLookup)
547   {
548     mDefaultPropertyLookup = new DefaultPropertyLookup();
549
550     for (int i=0; i<DEFAULT_PROPERTY_COUNT; ++i)
551     {
552       (*mDefaultPropertyLookup)[DEFAULT_PROPERTY_NAMES[i]] = i;
553     }
554   }
555   DALI_ASSERT_DEBUG( NULL != mDefaultPropertyLookup );
556
557   // Look for name in default properties
558   DefaultPropertyLookup::const_iterator result = mDefaultPropertyLookup->find( name );
559   if ( mDefaultPropertyLookup->end() != result )
560   {
561     index = result->second;
562   }
563
564   return index;
565 }
566
567 bool ShaderEffect::IsDefaultPropertyWritable(Property::Index index) const
568 {
569   return true;
570 }
571
572 bool ShaderEffect::IsDefaultPropertyAnimatable(Property::Index index) const
573 {
574   return false;
575 }
576
577 bool ShaderEffect::IsDefaultPropertyAConstraintInput( Property::Index index ) const
578 {
579   return false;
580 }
581
582 Property::Type ShaderEffect::GetDefaultPropertyType(Property::Index index) const
583 {
584   if( index < DEFAULT_PROPERTY_COUNT )
585   {
586     return DEFAULT_PROPERTY_TYPES[index];
587   }
588   else
589   {
590     // index out of range...return Property::NONE
591     return Property::NONE;
592   }
593 }
594
595 void ShaderEffect::SetDefaultProperty( Property::Index index, const Property::Value& propertyValue )
596 {
597   switch ( index )
598   {
599     case Dali::ShaderEffect::GRID_DENSITY:
600     {
601       SetGridDensityMessage( mUpdateManager.GetEventToUpdate(), *mSceneObject, propertyValue.Get<float>() );
602       break;
603     }
604
605     case Dali::ShaderEffect::IMAGE:
606     {
607       Dali::Image img(Scripting::NewImage( propertyValue ));
608       if(img)
609       {
610         SetEffectImage( img );
611       }
612       else
613       {
614         DALI_LOG_WARNING("Cannot create image from property value for ShaderEffect image\n");
615       }
616       break;
617     }
618
619     case Dali::ShaderEffect::PROGRAM:
620     {
621       std::string vertexPrefix   = GetShader("vertex-prefix", propertyValue);
622       std::string fragmentPrefix = GetShader("fragment-prefix", propertyValue);
623       std::string vertex         = GetShader("vertex", propertyValue);
624       std::string fragment       = GetShader("fragment", propertyValue);
625
626       GeometryType geometryType      = GEOMETRY_TYPE_IMAGE;
627
628       if( propertyValue.HasKey("geometry-type") )
629       {
630         Property::Value geometryValue  = propertyValue.GetValue("geometry-type");
631         DALI_ASSERT_ALWAYS(geometryValue.GetType() == Property::STRING && "Geometry type is not a string" );
632
633         std::string s = geometryValue.Get<std::string>();
634         if(s == "GEOMETRY_TYPE_IMAGE")
635         {
636           geometryType  = GEOMETRY_TYPE_IMAGE;
637         }
638         else if (s == "GEOMETRY_TYPE_TEXT")
639         {
640           geometryType  = GEOMETRY_TYPE_TEXT;
641         }
642         else if( s == "GEOMETRY_TYPE_MESH")
643         {
644           geometryType  = GEOMETRY_TYPE_MESH;
645         }
646         else if( s == "GEOMETRY_TYPE_TEXTURED_MESH")
647         {
648           geometryType  = GEOMETRY_TYPE_TEXTURED_MESH;
649         }
650         else
651         {
652           DALI_ASSERT_ALWAYS(!"Geometry type unknown" );
653         }
654       }
655       SetShaderProgram( vertexPrefix, vertex, fragmentPrefix, fragment, geometryType, ShaderEffectPtr(this) );
656       break;
657     }
658
659     case Dali::ShaderEffect::GEOMETRY_HINTS:
660     {
661       Dali::ShaderEffect::GeometryHints hint = Dali::ShaderEffect::HINT_NONE;
662       Property::Value geometryHintsValue   = propertyValue.GetValue("geometry-hints");
663
664       std::string s = geometryHintsValue.Get<std::string>();
665       if(s == "HINT_NONE")
666       {
667         hint = Dali::ShaderEffect::HINT_NONE;
668       }
669       else if(s == "HINT_GRID_X")
670       {
671         hint = Dali::ShaderEffect::HINT_GRID_X;
672       }
673       else if(s == "HINT_GRID_Y")
674       {
675         hint = Dali::ShaderEffect::HINT_GRID_Y;
676       }
677       else if(s == "HINT_GRID")
678       {
679         hint = Dali::ShaderEffect::HINT_GRID;
680       }
681       else if(s == "HINT_DEPTH_BUFFER")
682       {
683         hint = Dali::ShaderEffect::HINT_DEPTH_BUFFER;
684       }
685       else if(s == "HINT_BLENDING")
686       {
687         hint = Dali::ShaderEffect::HINT_BLENDING;
688       }
689       else
690       {
691         DALI_ASSERT_ALWAYS(!"Geometry hint unknown" );
692       }
693
694       SetHintsMessage( mUpdateManager.GetEventToUpdate(), *mSceneObject, hint );
695
696       break;
697     }
698
699     default:
700     {
701       DALI_ASSERT_ALWAYS(false && "ShaderEffect property enumeration out of range"); // should not come here
702       break;
703     }
704   }
705 }
706
707 Property::Value ShaderEffect::GetDefaultProperty(Property::Index /*index*/) const
708 {
709   // none of our properties are readable so return empty
710   return Property::Value();
711 }
712
713 void ShaderEffect::InstallSceneObjectProperty( PropertyBase& newProperty, const std::string& name, unsigned int index )
714 {
715   // 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)
716
717   // mSceneObject is being used in a separate thread; queue a message to add the property
718   InstallCustomPropertyMessage( mUpdateManager.GetEventToUpdate(), *mSceneObject, newProperty ); // Message takes ownership
719
720   // mSceneObject requires metadata for each custom property (uniform)
721   UniformMeta* meta = UniformMeta::New( name, newProperty, Dali::ShaderEffect::COORDINATE_TYPE_DEFAULT );
722   // mSceneObject is being used in a separate thread; queue a message to add the property
723   InstallUniformMetaMessage( mUpdateManager.GetEventToUpdate(), *mSceneObject, *meta ); // Message takes ownership
724
725   // Add entry to the metadata lookup
726   mCustomMetadata[index] = meta;
727 }
728
729 const SceneGraph::PropertyOwner* ShaderEffect::GetSceneObject() const
730 {
731   return mSceneObject;
732 }
733
734 const PropertyBase* ShaderEffect::GetSceneObjectAnimatableProperty( Property::Index index ) const
735 {
736   CustomPropertyLookup::const_iterator entry = GetCustomPropertyLookup().find( index );
737
738   DALI_ASSERT_ALWAYS( GetCustomPropertyLookup().end() != entry && "Property index is invalid" );
739
740   DALI_ASSERT_ALWAYS( entry->second.IsAnimatable() && "shader effect has only animatable properties" );
741
742   return dynamic_cast<const PropertyBase*>( entry->second.GetSceneGraphProperty() );
743 }
744
745 const PropertyInputImpl* ShaderEffect::GetSceneObjectInputProperty( Property::Index index ) const
746 {
747   CustomPropertyLookup::const_iterator entry = GetCustomPropertyLookup().find( index );
748
749   DALI_ASSERT_ALWAYS( GetCustomPropertyLookup().end() != entry && "Property index is invalid" );
750
751   DALI_ASSERT_ALWAYS( entry->second.IsAnimatable() && "shader effect has only animatable properties" );
752
753   return entry->second.GetSceneGraphProperty();
754 }
755
756 } // namespace Internal
757
758 } // namespace Dali