2 * Copyright (c) 2014 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <dali/internal/event/effects/shader-effect-impl.h>
22 #include <cstring> // for strcmp
25 #include <dali/public-api/math/matrix.h>
26 #include <dali/public-api/math/matrix3.h>
27 #include <dali/public-api/math/vector2.h>
28 #include <dali/public-api/object/type-registry.h>
29 #include <dali/devel-api/scripting/scripting.h>
30 #include <dali/public-api/shader-effects/shader-effect.h>
31 #include <dali/internal/event/actors/image-actor-impl.h>
32 #include <dali/internal/event/common/property-helper.h>
33 #include <dali/internal/event/images/image-impl.h>
34 #include "dali-shaders.h"
49 // Name Type writable animatable constraint-input enum for index-checking
50 DALI_PROPERTY_TABLE_BEGIN
51 DALI_PROPERTY( "gridDensity", FLOAT, true, false, false, Dali::ShaderEffect::Property::GRID_DENSITY )
52 DALI_PROPERTY( "image", MAP, true, false, false, Dali::ShaderEffect::Property::IMAGE )
53 DALI_PROPERTY( "program", MAP, true, false, false, Dali::ShaderEffect::Property::PROGRAM )
54 DALI_PROPERTY( "geometryHints", STRING, true, false, false, Dali::ShaderEffect::Property::GEOMETRY_HINTS )
55 DALI_PROPERTY_TABLE_END( DEFAULT_ACTOR_PROPERTY_START_INDEX )
59 Internal::ShaderEffectPtr internal = Internal::ShaderEffect::New();
61 return Dali::ShaderEffect(internal.Get());
64 TypeRegistration mType( typeid(Dali::ShaderEffect), typeid(Dali::Handle), Create );
68 const char* vertexShaderPrefix;
69 const char* fragmentShaderPrefix;
70 const char* vertexShaderPostfix;
71 const char* fragmentShaderPostfix;
74 WrapperStrings customImageShaderWrappers =
76 CustomImagePrefixVertex, CustomImagePrefixFragment,
77 CustomImagePostfixVertex, CustomImagePostfixFragment
81 * Helper to wrap the program with our default pre and postfix if needed
82 * @param[in] vertexPrefix from application
83 * @param[in] vertexBody from application
85 std::string WrapVertexShader( const std::string& vertexPrefix, const std::string& vertexBody )
87 std::string vertexSource = vertexPrefix + customImageShaderWrappers.vertexShaderPrefix;
89 // Append the custom vertex shader code if supplied, otherwise append the default
90 if ( vertexBody.length() > 0 )
92 vertexSource.append( vertexBody );
96 vertexSource.append( customImageShaderWrappers.vertexShaderPostfix );
103 * Helper to wrap the program with our default pre and postfix if needed
104 * @param[in] fragmentPrefix from application
105 * @param[in] fragmentBody from application
107 std::string WrapFragmentShader( const std::string& fragmentPrefix, const std::string& fragmentBody )
109 std::string fragmentSource = fragmentPrefix + customImageShaderWrappers.fragmentShaderPrefix;
111 // Append the custom fragment shader code if supplied, otherwise append the default
112 if ( fragmentBody.length() > 0 )
114 fragmentSource.append( fragmentBody );
118 fragmentSource.append( customImageShaderWrappers.fragmentShaderPostfix );
121 return fragmentSource;
124 std::string GetStringProperty(const std::string& field, const Property::Value& property)
127 const Property::Map* map = property.GetMap();
130 const Property::Value* value = map->Find( field );
133 value->Get( retval );
140 Dali::Shader::Hint::Value ConvertHints( Dali::ShaderEffect::GeometryHints hints)
142 int convertedHints = Dali::Shader::Hint::NONE;
144 if( hints & Dali::ShaderEffect::HINT_BLENDING )
146 convertedHints |= Dali::Shader::Hint::OUTPUT_IS_TRANSPARENT;
148 if( !(hints & Dali::ShaderEffect::HINT_DOESNT_MODIFY_GEOMETRY) )
150 convertedHints |= Dali::Shader::Hint::MODIFIES_GEOMETRY;
153 return Dali::Shader::Hint::Value( convertedHints );
156 } // unnamed namespace
158 ShaderEffectPtr ShaderEffect::New( Dali::ShaderEffect::GeometryHints hints )
160 ShaderEffectPtr shaderEffect( new ShaderEffect( hints ) );
161 shaderEffect->RegisterObject();
165 ShaderEffect::ShaderEffect( Dali::ShaderEffect::GeometryHints hints )
166 : mGridDensity( Dali::ShaderEffect::DEFAULT_GRID_DENSITY ),
167 mGeometryHints( hints )
171 ShaderEffect::~ShaderEffect()
173 // Guard to allow handle destruction after Core has been destroyed
177 void ShaderEffect::SetEffectImage( Dali::Image image )
179 // if images are the same, do nothing
180 if ( mEffectImage == image )
185 if ( mEffectImage && mConnectedActors.size() > 0 )
187 // unset previous image
188 GetImplementation( mEffectImage ).Disconnect();
191 // in case image is empty this will reset our image handle
192 mEffectImage = image;
196 // tell image that we're using it
197 if (mConnectedActors.size() > 0)
199 GetImplementation( mEffectImage ).Connect();
203 //inform connected actors the image has been unset
204 for(std::vector< ActorPtr >::iterator it = mConnectedActors.begin(); it != mConnectedActors.end(); ++it )
206 ImageActor* imageActor = dynamic_cast< ImageActor* >( it->Get() );
209 imageActor->EffectImageUpdated();
214 void ShaderEffect::SetUniform( const std::string& name, Property::Value value, UniformCoordinateType uniformCoordinateType )
216 // Register the property if it does not exist
217 mShader->RegisterProperty( name, value );
220 void ShaderEffect::SetPrograms( const string& vertexSource, const string& fragmentSource )
222 SetPrograms( "", "", vertexSource, fragmentSource );
225 void ShaderEffect::SetPrograms( const std::string& vertexPrefix, const std::string& fragmentPrefix,
226 const std::string& vertexSource, const std::string& fragmentSource )
228 mShader = Shader::New( WrapVertexShader( vertexPrefix, vertexSource ),
229 WrapFragmentShader( fragmentPrefix, fragmentSource ),
230 ConvertHints( mGeometryHints ) );
233 Vector2 ShaderEffect::GetGridSize( const Vector2& size )
235 Vector2 gridSize( 1.f, 1.f );
237 if( mGridDensity > 0 )
239 if( ( mGeometryHints & Dali::ShaderEffect::HINT_GRID_X ) )
241 gridSize.x = ceil( size.width / mGridDensity );
243 if( ( mGeometryHints & Dali::ShaderEffect::HINT_GRID_Y ) )
245 gridSize.y = ceil( size.height / mGridDensity );
252 void ShaderEffect::Connect( ActorPtr actor )
259 std::vector< ActorPtr >::const_iterator it = std::find( mConnectedActors.begin(), mConnectedActors.end(), actor );
260 if( it == mConnectedActors.end() )
262 mConnectedActors.push_back( actor );
265 if( mEffectImage && mConnectedActors.size() == 1 )
267 GetImplementation( mEffectImage ).Connect();
270 void ShaderEffect::Disconnect( ActorPtr actor )
277 DALI_ASSERT_DEBUG(mConnectedActors.size() > 0);
278 std::vector< ActorPtr >::iterator match( std::remove( mConnectedActors.begin(), mConnectedActors.end(), actor ) );
279 mConnectedActors.erase( match, mConnectedActors.end() );
281 if (mEffectImage && mConnectedActors.size() == 0)
283 GetImplementation(mEffectImage).Disconnect();
287 unsigned int ShaderEffect::GetPropertyCount() const
289 return GetDefaultPropertyCount() + mShader->GetPropertyCount();
292 std::string ShaderEffect::GetPropertyName( Property::Index index ) const
294 if ( index < DEFAULT_PROPERTY_COUNT )
296 return GetDefaultPropertyName( index );
300 return mShader->GetPropertyName( index );
304 Property::Index ShaderEffect::GetPropertyIndex( const std::string& name ) const
306 Property::Index index = GetDefaultPropertyIndex( name );
307 if( index == Property::INVALID_INDEX )
309 return mShader->GetPropertyIndex( name );
317 bool ShaderEffect::IsPropertyWritable( Property::Index index ) const
319 if ( index < DEFAULT_PROPERTY_COUNT )
321 return IsDefaultPropertyWritable( index );
325 return mShader->IsPropertyWritable( index );
329 bool ShaderEffect::IsPropertyAnimatable( Property::Index index ) const
331 if ( index < DEFAULT_PROPERTY_COUNT )
333 return IsDefaultPropertyAnimatable( index );
337 return mShader->IsPropertyAnimatable( index );
341 bool ShaderEffect::IsPropertyAConstraintInput( Property::Index index ) const
343 if ( index < DEFAULT_PROPERTY_COUNT )
345 return IsDefaultPropertyAConstraintInput( index );
349 return mShader->IsPropertyAConstraintInput( index );
353 Property::Type ShaderEffect::GetPropertyType( Property::Index index ) const
355 if ( index < DEFAULT_PROPERTY_COUNT )
357 return GetDefaultPropertyType( index );
359 return mShader->GetPropertyType( index );
362 void ShaderEffect::SetProperty( Property::Index index, const Property::Value& propertyValue )
364 if ( index < DEFAULT_PROPERTY_COUNT )
366 SetDefaultProperty( index, propertyValue );
370 mShader->SetProperty( index, propertyValue );
374 Property::Value ShaderEffect::GetProperty( Property::Index index ) const
376 if ( index < DEFAULT_PROPERTY_COUNT )
378 return GetDefaultProperty( index );
380 return mShader->GetProperty( index );
383 void ShaderEffect::GetPropertyIndices( Property::IndexContainer& indices ) const
385 mShader->GetPropertyIndices( indices );
386 GetDefaultPropertyIndices( indices );
389 Property::Index ShaderEffect::RegisterProperty( const std::string& name, const Property::Value& propertyValue )
391 return mShader->RegisterProperty( name, propertyValue );
394 Property::Index ShaderEffect::RegisterProperty( const std::string& name, const Property::Value& propertyValue, Property::AccessMode accessMode )
396 return mShader->RegisterProperty( name, propertyValue, accessMode );
399 Dali::PropertyNotification ShaderEffect::AddPropertyNotification( Property::Index index,
401 const Dali::PropertyCondition& condition )
403 return mShader->AddPropertyNotification( index, componentIndex, condition );
406 void ShaderEffect::RemovePropertyNotification( Dali::PropertyNotification propertyNotification )
408 mShader->RemovePropertyNotification( propertyNotification );
411 void ShaderEffect::RemovePropertyNotifications()
413 mShader->RemovePropertyNotifications();
416 unsigned int ShaderEffect::GetDefaultPropertyCount() const
418 return DEFAULT_PROPERTY_COUNT;
421 void ShaderEffect::GetDefaultPropertyIndices( Property::IndexContainer& indices ) const
423 indices.Reserve( indices.Size() + DEFAULT_PROPERTY_COUNT );
425 for ( int i = 0; i < DEFAULT_PROPERTY_COUNT; ++i )
427 indices.PushBack( i );
431 const char* ShaderEffect::GetDefaultPropertyName(Property::Index index) const
433 if( index < DEFAULT_PROPERTY_COUNT )
435 return DEFAULT_PROPERTY_DETAILS[index].name;
441 Property::Index ShaderEffect::GetDefaultPropertyIndex(const std::string& name) const
443 Property::Index index = Property::INVALID_INDEX;
445 // Look for name in default properties
446 for( int i = 0; i < DEFAULT_PROPERTY_COUNT; ++i )
448 const Internal::PropertyDetails* property = &DEFAULT_PROPERTY_DETAILS[ i ];
449 if( 0 == strcmp( name.c_str(), property->name ) ) // dont want to convert rhs to string
459 bool ShaderEffect::IsDefaultPropertyWritable(Property::Index index) const
461 return DEFAULT_PROPERTY_DETAILS[ index ].writable;
464 bool ShaderEffect::IsDefaultPropertyAnimatable(Property::Index index) const
466 return DEFAULT_PROPERTY_DETAILS[ index ].animatable;
469 bool ShaderEffect::IsDefaultPropertyAConstraintInput( Property::Index index ) const
471 return DEFAULT_PROPERTY_DETAILS[ index ].constraintInput;
474 Property::Type ShaderEffect::GetDefaultPropertyType(Property::Index index) const
476 if( index < DEFAULT_PROPERTY_COUNT )
478 return DEFAULT_PROPERTY_DETAILS[index].type;
481 // index out of range...return Property::NONE
482 return Property::NONE;
485 void ShaderEffect::SetDefaultProperty( Property::Index index, const Property::Value& propertyValue )
489 case Dali::ShaderEffect::Property::GRID_DENSITY:
491 propertyValue.Get( mGridDensity );
492 if( ( mGeometryHints & Dali::ShaderEffect::HINT_GRID_X ) ||
493 ( mGeometryHints & Dali::ShaderEffect::HINT_GRID_Y ) )
495 //inform all the connected actors
496 for(std::vector< ActorPtr >::iterator it = mConnectedActors.begin(); it != mConnectedActors.end(); ++it )
498 (*it)->RelayoutRequest();
504 case Dali::ShaderEffect::Property::IMAGE:
506 Dali::Image img(Scripting::NewImage( propertyValue ));
509 SetEffectImage( img );
513 DALI_LOG_WARNING("Cannot create image from property value for ShaderEffect image\n");
518 case Dali::ShaderEffect::Property::PROGRAM:
520 std::string vertexPrefix = GetStringProperty("vertexPrefix", propertyValue);
521 std::string fragmentPrefix = GetStringProperty("fragmentPrefix", propertyValue);
522 std::string vertex = GetStringProperty("vertex", propertyValue);
523 std::string fragment = GetStringProperty("fragment", propertyValue);
525 SetPrograms( vertexPrefix, fragmentPrefix, vertex, fragment );
529 case Dali::ShaderEffect::Property::GEOMETRY_HINTS:
531 mGeometryHints = Dali::ShaderEffect::HINT_NONE;
532 std::string s = propertyValue.Get<std::string>();
535 mGeometryHints = Dali::ShaderEffect::HINT_NONE;
537 else if(s == "HINT_GRID_X")
539 mGeometryHints = Dali::ShaderEffect::HINT_GRID_X;
541 else if(s == "HINT_GRID_Y")
543 mGeometryHints = Dali::ShaderEffect::HINT_GRID_Y;
545 else if(s == "HINT_GRID")
547 mGeometryHints = Dali::ShaderEffect::HINT_GRID;
549 else if(s == "HINT_DEPTH_BUFFER")
551 mGeometryHints = Dali::ShaderEffect::HINT_DEPTH_BUFFER;
553 else if(s == "HINT_BLENDING")
555 mGeometryHints = Dali::ShaderEffect::HINT_BLENDING;
557 else if(s == "HINT_DOESNT_MODIFY_GEOMETRY")
559 mGeometryHints = Dali::ShaderEffect::HINT_DOESNT_MODIFY_GEOMETRY;
563 DALI_ASSERT_ALWAYS(!"Geometry hint unknown" );
576 Property::Value ShaderEffect::GetDefaultProperty(Property::Index /*index*/) const
578 // none of our properties are readable so return empty
579 return Property::Value();
582 const SceneGraph::PropertyOwner* ShaderEffect::GetSceneObject() const
584 return mShader->GetSceneObject();
587 const SceneGraph::PropertyBase* ShaderEffect::GetSceneObjectAnimatableProperty( Property::Index index ) const
589 return mShader->GetSceneObjectAnimatableProperty( index );
592 const PropertyInputImpl* ShaderEffect::GetSceneObjectInputProperty( Property::Index index ) const
594 return mShader->GetSceneObjectInputProperty( index );
597 int ShaderEffect::GetPropertyComponentIndex( Property::Index index ) const
599 return mShader->GetPropertyComponentIndex( index );
602 } // namespace Internal