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::ShaderHints ConvertHints( Dali::ShaderEffect::GeometryHints hints)
142 int convertedHints = Dali::Shader::HINT_NONE;
143 if( hints & Dali::ShaderEffect::HINT_DEPTH_BUFFER )
145 convertedHints |= Dali::Shader::HINT_REQUIRES_SELF_DEPTH_TEST;
147 if( hints & Dali::ShaderEffect::HINT_BLENDING )
149 convertedHints |= Dali::Shader::HINT_OUTPUT_IS_TRANSPARENT;
151 if( !(hints & Dali::ShaderEffect::HINT_DOESNT_MODIFY_GEOMETRY) )
153 convertedHints |= Dali::Shader::HINT_MODIFIES_GEOMETRY;
156 return Dali::Shader::ShaderHints( convertedHints );
159 } // unnamed namespace
161 ShaderEffectPtr ShaderEffect::New( Dali::ShaderEffect::GeometryHints hints )
163 ShaderEffectPtr shaderEffect( new ShaderEffect( hints ) );
164 shaderEffect->RegisterObject();
168 ShaderEffect::ShaderEffect( Dali::ShaderEffect::GeometryHints hints )
169 : mGridDensity( Dali::ShaderEffect::DEFAULT_GRID_DENSITY ),
170 mGeometryHints( hints )
174 ShaderEffect::~ShaderEffect()
176 // Guard to allow handle destruction after Core has been destroyed
180 void ShaderEffect::SetEffectImage( Dali::Image image )
182 // if images are the same, do nothing
183 if ( mEffectImage == image )
188 if ( mEffectImage && mConnectedActors.size() > 0 )
190 // unset previous image
191 GetImplementation( mEffectImage ).Disconnect();
194 // in case image is empty this will reset our image handle
195 mEffectImage = image;
199 // tell image that we're using it
200 if (mConnectedActors.size() > 0)
202 GetImplementation( mEffectImage ).Connect();
206 //inform connected actors the image has been unset
207 for(std::vector< ActorPtr >::iterator it = mConnectedActors.begin(); it != mConnectedActors.end(); ++it )
209 ImageActor* imageActor = dynamic_cast< ImageActor* >( it->Get() );
212 imageActor->EffectImageUpdated();
217 void ShaderEffect::SetUniform( const std::string& name, Property::Value value, UniformCoordinateType uniformCoordinateType )
219 // Register the property if it does not exist
220 mShader->RegisterProperty( name, value );
223 void ShaderEffect::SetPrograms( const string& vertexSource, const string& fragmentSource )
225 SetPrograms( "", "", vertexSource, fragmentSource );
228 void ShaderEffect::SetPrograms( const std::string& vertexPrefix, const std::string& fragmentPrefix,
229 const std::string& vertexSource, const std::string& fragmentSource )
231 mShader = Shader::New( WrapVertexShader( vertexPrefix, vertexSource ),
232 WrapFragmentShader( fragmentPrefix, fragmentSource ),
233 ConvertHints( mGeometryHints ) );
236 Vector2 ShaderEffect::GetGridSize( const Vector2& size )
238 Vector2 gridSize( 1.f, 1.f );
240 if( mGridDensity > 0 )
242 if( ( mGeometryHints & Dali::ShaderEffect::HINT_GRID_X ) )
244 gridSize.x = ceil( size.width / mGridDensity );
246 if( ( mGeometryHints & Dali::ShaderEffect::HINT_GRID_Y ) )
248 gridSize.y = ceil( size.height / mGridDensity );
255 void ShaderEffect::Connect( ActorPtr actor )
262 std::vector< ActorPtr >::const_iterator it = std::find( mConnectedActors.begin(), mConnectedActors.end(), actor );
263 if( it == mConnectedActors.end() )
265 mConnectedActors.push_back( actor );
268 if( mEffectImage && mConnectedActors.size() == 1 )
270 GetImplementation( mEffectImage ).Connect();
273 void ShaderEffect::Disconnect( ActorPtr actor )
280 DALI_ASSERT_DEBUG(mConnectedActors.size() > 0);
281 std::vector< ActorPtr >::iterator match( std::remove( mConnectedActors.begin(), mConnectedActors.end(), actor ) );
282 mConnectedActors.erase( match, mConnectedActors.end() );
284 if (mEffectImage && mConnectedActors.size() == 0)
286 GetImplementation(mEffectImage).Disconnect();
290 unsigned int ShaderEffect::GetPropertyCount() const
292 return GetDefaultPropertyCount() + mShader->GetPropertyCount();
295 std::string ShaderEffect::GetPropertyName( Property::Index index ) const
297 if ( index < DEFAULT_PROPERTY_COUNT )
299 return GetDefaultPropertyName( index );
303 return mShader->GetPropertyName( index );
307 Property::Index ShaderEffect::GetPropertyIndex( const std::string& name ) const
309 Property::Index index = GetDefaultPropertyIndex( name );
310 if( index == Property::INVALID_INDEX )
312 return mShader->GetPropertyIndex( name );
320 bool ShaderEffect::IsPropertyWritable( Property::Index index ) const
322 if ( index < DEFAULT_PROPERTY_COUNT )
324 return IsDefaultPropertyWritable( index );
328 return mShader->IsPropertyWritable( index );
332 bool ShaderEffect::IsPropertyAnimatable( Property::Index index ) const
334 if ( index < DEFAULT_PROPERTY_COUNT )
336 return IsDefaultPropertyAnimatable( index );
340 return mShader->IsPropertyAnimatable( index );
344 bool ShaderEffect::IsPropertyAConstraintInput( Property::Index index ) const
346 if ( index < DEFAULT_PROPERTY_COUNT )
348 return IsDefaultPropertyAConstraintInput( index );
352 return mShader->IsPropertyAConstraintInput( index );
356 Property::Type ShaderEffect::GetPropertyType( Property::Index index ) const
358 if ( index < DEFAULT_PROPERTY_COUNT )
360 return GetDefaultPropertyType( index );
362 return mShader->GetPropertyType( index );
365 void ShaderEffect::SetProperty( Property::Index index, const Property::Value& propertyValue )
367 if ( index < DEFAULT_PROPERTY_COUNT )
369 SetDefaultProperty( index, propertyValue );
373 mShader->SetProperty( index, propertyValue );
377 Property::Value ShaderEffect::GetProperty( Property::Index index ) const
379 if ( index < DEFAULT_PROPERTY_COUNT )
381 return GetDefaultProperty( index );
383 return mShader->GetProperty( index );
386 void ShaderEffect::GetPropertyIndices( Property::IndexContainer& indices ) const
388 mShader->GetPropertyIndices( indices );
389 GetDefaultPropertyIndices( indices );
392 Property::Index ShaderEffect::RegisterProperty( const std::string& name, const Property::Value& propertyValue )
394 return mShader->RegisterProperty( name, propertyValue );
397 Property::Index ShaderEffect::RegisterProperty( const std::string& name, const Property::Value& propertyValue, Property::AccessMode accessMode )
399 return mShader->RegisterProperty( name, propertyValue, accessMode );
402 Dali::PropertyNotification ShaderEffect::AddPropertyNotification( Property::Index index,
404 const Dali::PropertyCondition& condition )
406 return mShader->AddPropertyNotification( index, componentIndex, condition );
409 void ShaderEffect::RemovePropertyNotification( Dali::PropertyNotification propertyNotification )
411 mShader->RemovePropertyNotification( propertyNotification );
414 void ShaderEffect::RemovePropertyNotifications()
416 mShader->RemovePropertyNotifications();
419 unsigned int ShaderEffect::GetDefaultPropertyCount() const
421 return DEFAULT_PROPERTY_COUNT;
424 void ShaderEffect::GetDefaultPropertyIndices( Property::IndexContainer& indices ) const
426 indices.Reserve( indices.Size() + DEFAULT_PROPERTY_COUNT );
428 for ( int i = 0; i < DEFAULT_PROPERTY_COUNT; ++i )
430 indices.PushBack( i );
434 const char* ShaderEffect::GetDefaultPropertyName(Property::Index index) const
436 if( index < DEFAULT_PROPERTY_COUNT )
438 return DEFAULT_PROPERTY_DETAILS[index].name;
444 Property::Index ShaderEffect::GetDefaultPropertyIndex(const std::string& name) const
446 Property::Index index = Property::INVALID_INDEX;
448 // Look for name in default properties
449 for( int i = 0; i < DEFAULT_PROPERTY_COUNT; ++i )
451 const Internal::PropertyDetails* property = &DEFAULT_PROPERTY_DETAILS[ i ];
452 if( 0 == strcmp( name.c_str(), property->name ) ) // dont want to convert rhs to string
462 bool ShaderEffect::IsDefaultPropertyWritable(Property::Index index) const
464 return DEFAULT_PROPERTY_DETAILS[ index ].writable;
467 bool ShaderEffect::IsDefaultPropertyAnimatable(Property::Index index) const
469 return DEFAULT_PROPERTY_DETAILS[ index ].animatable;
472 bool ShaderEffect::IsDefaultPropertyAConstraintInput( Property::Index index ) const
474 return DEFAULT_PROPERTY_DETAILS[ index ].constraintInput;
477 Property::Type ShaderEffect::GetDefaultPropertyType(Property::Index index) const
479 if( index < DEFAULT_PROPERTY_COUNT )
481 return DEFAULT_PROPERTY_DETAILS[index].type;
484 // index out of range...return Property::NONE
485 return Property::NONE;
488 void ShaderEffect::SetDefaultProperty( Property::Index index, const Property::Value& propertyValue )
492 case Dali::ShaderEffect::Property::GRID_DENSITY:
494 propertyValue.Get( mGridDensity );
495 if( ( mGeometryHints & Dali::ShaderEffect::HINT_GRID_X ) ||
496 ( mGeometryHints & Dali::ShaderEffect::HINT_GRID_Y ) )
498 //inform all the connected actors
499 for(std::vector< ActorPtr >::iterator it = mConnectedActors.begin(); it != mConnectedActors.end(); ++it )
501 (*it)->RelayoutRequest();
507 case Dali::ShaderEffect::Property::IMAGE:
509 Dali::Image img(Scripting::NewImage( propertyValue ));
512 SetEffectImage( img );
516 DALI_LOG_WARNING("Cannot create image from property value for ShaderEffect image\n");
521 case Dali::ShaderEffect::Property::PROGRAM:
523 std::string vertexPrefix = GetStringProperty("vertexPrefix", propertyValue);
524 std::string fragmentPrefix = GetStringProperty("fragmentPrefix", propertyValue);
525 std::string vertex = GetStringProperty("vertex", propertyValue);
526 std::string fragment = GetStringProperty("fragment", propertyValue);
528 SetPrograms( vertexPrefix, fragmentPrefix, vertex, fragment );
532 case Dali::ShaderEffect::Property::GEOMETRY_HINTS:
534 mGeometryHints = Dali::ShaderEffect::HINT_NONE;
535 std::string s = propertyValue.Get<std::string>();
538 mGeometryHints = Dali::ShaderEffect::HINT_NONE;
540 else if(s == "HINT_GRID_X")
542 mGeometryHints = Dali::ShaderEffect::HINT_GRID_X;
544 else if(s == "HINT_GRID_Y")
546 mGeometryHints = Dali::ShaderEffect::HINT_GRID_Y;
548 else if(s == "HINT_GRID")
550 mGeometryHints = Dali::ShaderEffect::HINT_GRID;
552 else if(s == "HINT_DEPTH_BUFFER")
554 mGeometryHints = Dali::ShaderEffect::HINT_DEPTH_BUFFER;
556 else if(s == "HINT_BLENDING")
558 mGeometryHints = Dali::ShaderEffect::HINT_BLENDING;
560 else if(s == "HINT_DOESNT_MODIFY_GEOMETRY")
562 mGeometryHints = Dali::ShaderEffect::HINT_DOESNT_MODIFY_GEOMETRY;
566 DALI_ASSERT_ALWAYS(!"Geometry hint unknown" );
579 Property::Value ShaderEffect::GetDefaultProperty(Property::Index /*index*/) const
581 // none of our properties are readable so return empty
582 return Property::Value();
585 const SceneGraph::PropertyOwner* ShaderEffect::GetSceneObject() const
587 return mShader->GetSceneObject();
590 const SceneGraph::PropertyBase* ShaderEffect::GetSceneObjectAnimatableProperty( Property::Index index ) const
592 return mShader->GetSceneObjectAnimatableProperty( index );
595 const PropertyInputImpl* ShaderEffect::GetSceneObjectInputProperty( Property::Index index ) const
597 return mShader->GetSceneObjectInputProperty( index );
600 int ShaderEffect::GetPropertyComponentIndex( Property::Index index ) const
602 return mShader->GetPropertyComponentIndex( index );
605 } // namespace Internal