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/devel-api/shader-effects/shader-effect.h>
31 #include <dali/internal/event/common/property-helper.h>
32 #include <dali/internal/event/images/image-impl.h>
33 #include "dali-shaders.h"
48 // Name Type writable animatable constraint-input enum for index-checking
49 DALI_PROPERTY_TABLE_BEGIN
50 DALI_PROPERTY( "gridDensity", FLOAT, true, false, false, Dali::ShaderEffect::Property::GRID_DENSITY )
51 DALI_PROPERTY( "image", MAP, true, false, false, Dali::ShaderEffect::Property::IMAGE )
52 DALI_PROPERTY( "program", MAP, true, false, false, Dali::ShaderEffect::Property::PROGRAM )
53 DALI_PROPERTY( "geometryHints", STRING, true, false, false, Dali::ShaderEffect::Property::GEOMETRY_HINTS )
54 DALI_PROPERTY_TABLE_END( DEFAULT_ACTOR_PROPERTY_START_INDEX )
58 Internal::ShaderEffectPtr internal = Internal::ShaderEffect::New();
60 return Dali::ShaderEffect(internal.Get());
63 TypeRegistration mType( typeid(Dali::ShaderEffect), typeid(Dali::Handle), Create );
67 const char* vertexShaderPrefix;
68 const char* fragmentShaderPrefix;
69 const char* vertexShaderPostfix;
70 const char* fragmentShaderPostfix;
73 WrapperStrings customImageShaderWrappers =
75 CustomImagePrefixVertex, CustomImagePrefixFragment,
76 CustomImagePostfixVertex, CustomImagePostfixFragment
80 * Helper to wrap the program with our default pre and postfix if needed
81 * @param[in] vertexPrefix from application
82 * @param[in] vertexBody from application
84 std::string WrapVertexShader( const std::string& vertexPrefix, const std::string& vertexBody )
86 std::string vertexSource = vertexPrefix + customImageShaderWrappers.vertexShaderPrefix;
88 // Append the custom vertex shader code if supplied, otherwise append the default
89 if ( vertexBody.length() > 0 )
91 vertexSource.append( vertexBody );
95 vertexSource.append( customImageShaderWrappers.vertexShaderPostfix );
102 * Helper to wrap the program with our default pre and postfix if needed
103 * @param[in] fragmentPrefix from application
104 * @param[in] fragmentBody from application
106 std::string WrapFragmentShader( const std::string& fragmentPrefix, const std::string& fragmentBody )
108 std::string fragmentSource = fragmentPrefix + customImageShaderWrappers.fragmentShaderPrefix;
110 // Append the custom fragment shader code if supplied, otherwise append the default
111 if ( fragmentBody.length() > 0 )
113 fragmentSource.append( fragmentBody );
117 fragmentSource.append( customImageShaderWrappers.fragmentShaderPostfix );
120 return fragmentSource;
123 std::string GetStringProperty(const std::string& field, const Property::Value& property)
126 const Property::Map* map = property.GetMap();
129 const Property::Value* value = map->Find( field );
132 value->Get( retval );
139 Dali::Shader::Hint::Value ConvertHints( Dali::ShaderEffect::GeometryHints hints)
141 int convertedHints = Dali::Shader::Hint::NONE;
143 if( hints & Dali::ShaderEffect::HINT_BLENDING )
145 convertedHints |= Dali::Shader::Hint::OUTPUT_IS_TRANSPARENT;
147 if( !(hints & Dali::ShaderEffect::HINT_DOESNT_MODIFY_GEOMETRY) )
149 convertedHints |= Dali::Shader::Hint::MODIFIES_GEOMETRY;
152 return Dali::Shader::Hint::Value( convertedHints );
155 } // unnamed namespace
157 ShaderEffectPtr ShaderEffect::New( Dali::ShaderEffect::GeometryHints hints )
159 ShaderEffectPtr shaderEffect( new ShaderEffect( hints ) );
160 shaderEffect->RegisterObject();
164 ShaderEffect::ShaderEffect( Dali::ShaderEffect::GeometryHints hints )
165 : mGridDensity( Dali::ShaderEffect::DEFAULT_GRID_DENSITY ),
166 mGeometryHints( hints )
170 ShaderEffect::~ShaderEffect()
172 // Guard to allow handle destruction after Core has been destroyed
176 void ShaderEffect::SetEffectImage( Dali::Image image )
178 // if images are the same, do nothing
179 if ( mEffectImage == image )
184 if ( mEffectImage && mConnectedActors.size() > 0 )
186 // unset previous image
187 GetImplementation( mEffectImage ).Disconnect();
190 // in case image is empty this will reset our image handle
191 mEffectImage = image;
195 // tell image that we're using it
196 if (mConnectedActors.size() > 0)
198 GetImplementation( mEffectImage ).Connect();
202 //inform connected actors the image has been unset
203 // TODO or CHECK: ImageActor part was removed.
206 void ShaderEffect::SetUniform( const std::string& name, Property::Value value, UniformCoordinateType uniformCoordinateType )
208 // Register the property if it does not exist
209 mShader->RegisterProperty( name, value );
212 void ShaderEffect::SetPrograms( const string& vertexSource, const string& fragmentSource )
214 SetPrograms( "", "", vertexSource, fragmentSource );
217 void ShaderEffect::SetPrograms( const std::string& vertexPrefix, const std::string& fragmentPrefix,
218 const std::string& vertexSource, const std::string& fragmentSource )
220 mShader = Shader::New( WrapVertexShader( vertexPrefix, vertexSource ),
221 WrapFragmentShader( fragmentPrefix, fragmentSource ),
222 ConvertHints( mGeometryHints ) );
225 Vector2 ShaderEffect::GetGridSize( const Vector2& size )
227 Vector2 gridSize( 1.f, 1.f );
229 if( mGridDensity > 0 )
231 if( ( mGeometryHints & Dali::ShaderEffect::HINT_GRID_X ) )
233 gridSize.x = ceil( size.width / mGridDensity );
235 if( ( mGeometryHints & Dali::ShaderEffect::HINT_GRID_Y ) )
237 gridSize.y = ceil( size.height / mGridDensity );
244 void ShaderEffect::Connect( ActorPtr actor )
251 std::vector< ActorPtr >::const_iterator it = std::find( mConnectedActors.begin(), mConnectedActors.end(), actor );
252 if( it == mConnectedActors.end() )
254 mConnectedActors.push_back( actor );
257 if( mEffectImage && mConnectedActors.size() == 1 )
259 GetImplementation( mEffectImage ).Connect();
262 void ShaderEffect::Disconnect( ActorPtr actor )
269 DALI_ASSERT_DEBUG(mConnectedActors.size() > 0);
270 std::vector< ActorPtr >::iterator match( std::remove( mConnectedActors.begin(), mConnectedActors.end(), actor ) );
271 mConnectedActors.erase( match, mConnectedActors.end() );
273 if (mEffectImage && mConnectedActors.size() == 0)
275 GetImplementation(mEffectImage).Disconnect();
279 unsigned int ShaderEffect::GetPropertyCount() const
281 return GetDefaultPropertyCount() + mShader->GetPropertyCount();
284 std::string ShaderEffect::GetPropertyName( Property::Index index ) const
286 if ( index < DEFAULT_PROPERTY_COUNT )
288 return GetDefaultPropertyName( index );
292 return mShader->GetPropertyName( index );
296 Property::Index ShaderEffect::GetPropertyIndex( const std::string& name ) const
298 Property::Index index = GetDefaultPropertyIndex( name );
299 if( index == Property::INVALID_INDEX )
301 return mShader->GetPropertyIndex( name );
309 bool ShaderEffect::IsPropertyWritable( Property::Index index ) const
311 if ( index < DEFAULT_PROPERTY_COUNT )
313 return IsDefaultPropertyWritable( index );
317 return mShader->IsPropertyWritable( index );
321 bool ShaderEffect::IsPropertyAnimatable( Property::Index index ) const
323 if ( index < DEFAULT_PROPERTY_COUNT )
325 return IsDefaultPropertyAnimatable( index );
329 return mShader->IsPropertyAnimatable( index );
333 bool ShaderEffect::IsPropertyAConstraintInput( Property::Index index ) const
335 if ( index < DEFAULT_PROPERTY_COUNT )
337 return IsDefaultPropertyAConstraintInput( index );
341 return mShader->IsPropertyAConstraintInput( index );
345 Property::Type ShaderEffect::GetPropertyType( Property::Index index ) const
347 if ( index < DEFAULT_PROPERTY_COUNT )
349 return GetDefaultPropertyType( index );
351 return mShader->GetPropertyType( index );
354 void ShaderEffect::SetProperty( Property::Index index, const Property::Value& propertyValue )
356 if ( index < DEFAULT_PROPERTY_COUNT )
358 SetDefaultProperty( index, propertyValue );
362 mShader->SetProperty( index, propertyValue );
366 Property::Value ShaderEffect::GetProperty( Property::Index index ) const
368 if ( index < DEFAULT_PROPERTY_COUNT )
370 return GetDefaultProperty( index );
372 return mShader->GetProperty( index );
375 void ShaderEffect::GetPropertyIndices( Property::IndexContainer& indices ) const
377 mShader->GetPropertyIndices( indices );
378 GetDefaultPropertyIndices( indices );
381 Property::Index ShaderEffect::RegisterProperty( const std::string& name, const Property::Value& propertyValue )
383 return mShader->RegisterProperty( name, propertyValue );
386 Property::Index ShaderEffect::RegisterProperty( const std::string& name, const Property::Value& propertyValue, Property::AccessMode accessMode )
388 return mShader->RegisterProperty( name, propertyValue, accessMode );
391 Dali::PropertyNotification ShaderEffect::AddPropertyNotification( Property::Index index,
393 const Dali::PropertyCondition& condition )
395 return mShader->AddPropertyNotification( index, componentIndex, condition );
398 void ShaderEffect::RemovePropertyNotification( Dali::PropertyNotification propertyNotification )
400 mShader->RemovePropertyNotification( propertyNotification );
403 void ShaderEffect::RemovePropertyNotifications()
405 mShader->RemovePropertyNotifications();
408 unsigned int ShaderEffect::GetDefaultPropertyCount() const
410 return DEFAULT_PROPERTY_COUNT;
413 void ShaderEffect::GetDefaultPropertyIndices( Property::IndexContainer& indices ) const
415 indices.Reserve( indices.Size() + DEFAULT_PROPERTY_COUNT );
417 for ( int i = 0; i < DEFAULT_PROPERTY_COUNT; ++i )
419 indices.PushBack( i );
423 const char* ShaderEffect::GetDefaultPropertyName(Property::Index index) const
425 if( index < DEFAULT_PROPERTY_COUNT )
427 return DEFAULT_PROPERTY_DETAILS[index].name;
433 Property::Index ShaderEffect::GetDefaultPropertyIndex(const std::string& name) const
435 Property::Index index = Property::INVALID_INDEX;
437 // Look for name in default properties
438 for( int i = 0; i < DEFAULT_PROPERTY_COUNT; ++i )
440 const Internal::PropertyDetails* property = &DEFAULT_PROPERTY_DETAILS[ i ];
441 if( 0 == strcmp( name.c_str(), property->name ) ) // dont want to convert rhs to string
451 bool ShaderEffect::IsDefaultPropertyWritable(Property::Index index) const
453 return DEFAULT_PROPERTY_DETAILS[ index ].writable;
456 bool ShaderEffect::IsDefaultPropertyAnimatable(Property::Index index) const
458 return DEFAULT_PROPERTY_DETAILS[ index ].animatable;
461 bool ShaderEffect::IsDefaultPropertyAConstraintInput( Property::Index index ) const
463 return DEFAULT_PROPERTY_DETAILS[ index ].constraintInput;
466 Property::Type ShaderEffect::GetDefaultPropertyType(Property::Index index) const
468 if( index < DEFAULT_PROPERTY_COUNT )
470 return DEFAULT_PROPERTY_DETAILS[index].type;
473 // index out of range...return Property::NONE
474 return Property::NONE;
477 void ShaderEffect::SetDefaultProperty( Property::Index index, const Property::Value& propertyValue )
481 case Dali::ShaderEffect::Property::GRID_DENSITY:
483 propertyValue.Get( mGridDensity );
484 if( ( mGeometryHints & Dali::ShaderEffect::HINT_GRID_X ) ||
485 ( mGeometryHints & Dali::ShaderEffect::HINT_GRID_Y ) )
487 //inform all the connected actors
488 for(std::vector< ActorPtr >::iterator it = mConnectedActors.begin(); it != mConnectedActors.end(); ++it )
490 (*it)->RelayoutRequest();
496 case Dali::ShaderEffect::Property::IMAGE:
498 Dali::Image img(Scripting::NewImage( propertyValue ));
501 SetEffectImage( img );
505 DALI_LOG_WARNING("Cannot create image from property value for ShaderEffect image\n");
510 case Dali::ShaderEffect::Property::PROGRAM:
512 std::string vertexPrefix = GetStringProperty("vertexPrefix", propertyValue);
513 std::string fragmentPrefix = GetStringProperty("fragmentPrefix", propertyValue);
514 std::string vertex = GetStringProperty("vertex", propertyValue);
515 std::string fragment = GetStringProperty("fragment", propertyValue);
517 SetPrograms( vertexPrefix, fragmentPrefix, vertex, fragment );
521 case Dali::ShaderEffect::Property::GEOMETRY_HINTS:
523 mGeometryHints = Dali::ShaderEffect::HINT_NONE;
524 std::string s = propertyValue.Get<std::string>();
527 mGeometryHints = Dali::ShaderEffect::HINT_NONE;
529 else if(s == "HINT_GRID_X")
531 mGeometryHints = Dali::ShaderEffect::HINT_GRID_X;
533 else if(s == "HINT_GRID_Y")
535 mGeometryHints = Dali::ShaderEffect::HINT_GRID_Y;
537 else if(s == "HINT_GRID")
539 mGeometryHints = Dali::ShaderEffect::HINT_GRID;
541 else if(s == "HINT_DEPTH_BUFFER")
543 mGeometryHints = Dali::ShaderEffect::HINT_DEPTH_BUFFER;
545 else if(s == "HINT_BLENDING")
547 mGeometryHints = Dali::ShaderEffect::HINT_BLENDING;
549 else if(s == "HINT_DOESNT_MODIFY_GEOMETRY")
551 mGeometryHints = Dali::ShaderEffect::HINT_DOESNT_MODIFY_GEOMETRY;
555 DALI_ASSERT_ALWAYS(!"Geometry hint unknown" );
568 Property::Value ShaderEffect::GetDefaultProperty(Property::Index /*index*/) const
570 // none of our properties are readable so return empty
571 return Property::Value();
574 const SceneGraph::PropertyOwner* ShaderEffect::GetSceneObject() const
576 return mShader->GetSceneObject();
579 const SceneGraph::PropertyBase* ShaderEffect::GetSceneObjectAnimatableProperty( Property::Index index ) const
581 return mShader->GetSceneObjectAnimatableProperty( index );
584 const PropertyInputImpl* ShaderEffect::GetSceneObjectInputProperty( Property::Index index ) const
586 return mShader->GetSceneObjectInputProperty( index );
589 int ShaderEffect::GetPropertyComponentIndex( Property::Index index ) const
591 return mShader->GetPropertyComponentIndex( index );
594 } // namespace Internal