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 <dali/public-api/math/matrix.h>
23 #include <dali/public-api/math/matrix3.h>
24 #include <dali/public-api/math/vector2.h>
25 #include <dali/public-api/object/type-registry.h>
26 #include <dali/devel-api/scripting/scripting.h>
27 #include <dali/public-api/shader-effects/shader-effect.h>
28 #include <dali/internal/event/actors/image-actor-impl.h>
29 #include <dali/internal/event/common/property-helper.h>
30 #include <dali/internal/event/common/stage-impl.h>
31 #include <dali/internal/event/common/thread-local-storage.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/render/shaders/scene-graph-shader.h>
36 #include <dali/internal/render/shaders/uniform-meta.h>
37 #include <dali/internal/update/animation/scene-graph-constraint-base.h>
38 #include <dali/internal/update/common/animatable-property.h>
39 #include <dali/internal/update/manager/update-manager.h>
40 #include "dali-shaders.h"
42 using Dali::Internal::SceneGraph::UpdateManager;
43 using Dali::Internal::SceneGraph::UniformMeta;
44 using Dali::Internal::SceneGraph::Shader;
45 using Dali::Internal::SceneGraph::AnimatableProperty;
46 using Dali::Internal::SceneGraph::PropertyBase;
47 using Dali::Internal::SceneGraph::RenderQueue;
61 // Name Type writable animatable constraint-input enum for index-checking
62 DALI_PROPERTY_TABLE_BEGIN
63 DALI_PROPERTY( "gridDensity", FLOAT, true, false, false, Dali::ShaderEffect::Property::GRID_DENSITY )
64 DALI_PROPERTY( "image", MAP, true, false, false, Dali::ShaderEffect::Property::IMAGE )
65 DALI_PROPERTY( "program", MAP, true, false, false, Dali::ShaderEffect::Property::PROGRAM )
66 DALI_PROPERTY( "geometryHints", STRING, true, false, false, Dali::ShaderEffect::Property::GEOMETRY_HINTS )
67 DALI_PROPERTY_TABLE_END( DEFAULT_ACTOR_PROPERTY_START_INDEX )
71 Internal::ShaderEffectPtr internal = Internal::ShaderEffect::New();
73 return Dali::ShaderEffect(internal.Get());
76 TypeRegistration mType( typeid(Dali::ShaderEffect), typeid(Dali::Handle), Create );
80 const char* vertexShaderPrefix;
81 const char* fragmentShaderPrefix;
82 const char* vertexShaderPostfix;
83 const char* fragmentShaderPostfix;
86 WrapperStrings customImageShaderWrappers =
88 CustomImagePrefixVertex, CustomImagePrefixFragment,
89 CustomImagePostfixVertex, CustomImagePostfixFragment
93 * Helper to wrap the program with our default pre and postfix if needed
94 * @param[in] vertexPrefix from application
95 * @param[in] vertexBody from application
97 std::string WrapVertexShader( const std::string& vertexPrefix, const std::string& vertexBody )
99 std::string vertexSource = vertexPrefix + customImageShaderWrappers.vertexShaderPrefix;
101 // Append the custom vertex shader code if supplied, otherwise append the default
102 if ( vertexBody.length() > 0 )
104 vertexSource.append( vertexBody );
108 vertexSource.append( customImageShaderWrappers.vertexShaderPostfix );
115 * Helper to wrap the program with our default pre and postfix if needed
116 * @param[in] fragmentPrefix from application
117 * @param[in] fragmentBody from application
119 std::string WrapFragmentShader( const std::string& fragmentPrefix, const std::string& fragmentBody )
121 std::string fragmentSource = fragmentPrefix + customImageShaderWrappers.fragmentShaderPrefix;
123 // Append the custom fragment shader code if supplied, otherwise append the default
124 if ( fragmentBody.length() > 0 )
126 fragmentSource.append( fragmentBody );
130 fragmentSource.append( customImageShaderWrappers.fragmentShaderPostfix );
133 return fragmentSource;
136 std::string GetShader(const std::string& field, const Property::Value& property)
139 const Property::Map* map = property.GetMap();
142 const Property::Value* value = map->Find( field );
145 value->Get( retval );
152 } // unnamed namespace
154 ShaderEffectPtr ShaderEffect::New( Dali::ShaderEffect::GeometryHints hints )
156 Stage* stage = Stage::GetCurrent();
160 ShaderEffectPtr shaderEffect( new ShaderEffect( *stage, hints ) );
161 shaderEffect->RegisterObject();
170 ShaderEffect::ShaderEffect( EventThreadServices& eventThreadServices, Dali::ShaderEffect::GeometryHints hints )
171 : mEventThreadServices( eventThreadServices ),
172 mGeometryHints( hints ),
173 mGridDensity( Dali::ShaderEffect::DEFAULT_GRID_DENSITY )
175 mSceneObject = new SceneGraph::Shader( hints );
176 DALI_ASSERT_DEBUG( NULL != mSceneObject );
178 // Transfer shader ownership to a scene message
179 AddShaderMessage( eventThreadServices.GetUpdateManager(), *mSceneObject );
182 ShaderEffect::~ShaderEffect()
184 // Guard to allow handle destruction after Core has been destroyed
185 if ( Stage::IsInstalled() )
187 // Remove scene-object using a message to the UpdateManager
190 RemoveShaderMessage( mEventThreadServices.GetUpdateManager(), *mSceneObject );
196 void ShaderEffect::SetEffectImage( Dali::Image image )
198 // if images are the same, do nothing
199 if ( mEffectImage == image )
204 if ( mEffectImage && mConnectedActors.size() > 0 )
206 // unset previous image
207 GetImplementation( mEffectImage ).Disconnect();
210 // in case image is empty this will reset our image handle
211 mEffectImage = image;
215 // tell image that we're using it
216 if (mConnectedActors.size() > 0)
218 GetImplementation( mEffectImage ).Connect();
222 //inform connected actors the image has been unset
223 for(std::vector< ActorPtr >::iterator it = mConnectedActors.begin(); it != mConnectedActors.end(); ++it )
225 ImageActor* imageActor = dynamic_cast< ImageActor* >( it->Get() );
228 imageActor->EffectImageUpdated();
233 void ShaderEffect::SetUniform( const std::string& name, Property::Value value, UniformCoordinateType uniformCoordinateType )
235 // Register the property if it does not exist
236 Property::Index index = RegisterProperty( name, value );
238 Uniform uniform = { name, index, value };
239 mUniforms.push_back( uniform );
241 //inform any connected actors
242 for(std::vector< ActorPtr >::iterator it = mConnectedActors.begin(); it != mConnectedActors.end(); ++it)
244 ImageActor* imageActor = dynamic_cast< ImageActor* >( (*it).Get() );
247 imageActor->EffectUniformUpdated( uniform );
252 void ShaderEffect::SetPrograms( const string& vertexSource, const string& fragmentSource )
254 SetPrograms( "", "", vertexSource, fragmentSource );
257 void ShaderEffect::SetPrograms( const std::string& vertexPrefix, const std::string& fragmentPrefix,
258 const std::string& vertexSource, const std::string& fragmentSource )
260 mVertexSource = WrapVertexShader( vertexPrefix, vertexSource );
261 mFragmentSource = WrapFragmentShader( fragmentPrefix, fragmentSource );
264 void ShaderEffect::Connect( ActorPtr actor )
271 std::vector< ActorPtr >::const_iterator it = std::find( mConnectedActors.begin(), mConnectedActors.end(), actor );
272 if( it == mConnectedActors.end() )
274 mConnectedActors.push_back( actor );
277 if( mEffectImage && mConnectedActors.size() == 1 )
279 GetImplementation( mEffectImage ).Connect();
282 void ShaderEffect::Disconnect( ActorPtr actor )
289 DALI_ASSERT_DEBUG(mConnectedActors.size() > 0);
290 std::vector< ActorPtr >::iterator match( std::remove( mConnectedActors.begin(), mConnectedActors.end(), actor ) );
291 mConnectedActors.erase( match, mConnectedActors.end() );
293 if (mEffectImage && mConnectedActors.size() == 0)
295 GetImplementation(mEffectImage).Disconnect();
299 unsigned int ShaderEffect::GetDefaultPropertyCount() const
301 return DEFAULT_PROPERTY_COUNT;
304 void ShaderEffect::GetDefaultPropertyIndices( Property::IndexContainer& indices ) const
306 indices.Reserve( DEFAULT_PROPERTY_COUNT );
308 for ( int i = 0; i < DEFAULT_PROPERTY_COUNT; ++i )
310 indices.PushBack( i );
314 const char* ShaderEffect::GetDefaultPropertyName(Property::Index index) const
316 if( index < DEFAULT_PROPERTY_COUNT )
318 return DEFAULT_PROPERTY_DETAILS[index].name;
324 Property::Index ShaderEffect::GetDefaultPropertyIndex(const std::string& name) const
326 Property::Index index = Property::INVALID_INDEX;
328 // Look for name in default properties
329 for( int i = 0; i < DEFAULT_PROPERTY_COUNT; ++i )
331 const Internal::PropertyDetails* property = &DEFAULT_PROPERTY_DETAILS[ i ];
332 if( 0 == strcmp( name.c_str(), property->name ) ) // dont want to convert rhs to string
342 bool ShaderEffect::IsDefaultPropertyWritable(Property::Index index) const
344 return DEFAULT_PROPERTY_DETAILS[ index ].writable;
347 bool ShaderEffect::IsDefaultPropertyAnimatable(Property::Index index) const
349 return DEFAULT_PROPERTY_DETAILS[ index ].animatable;
352 bool ShaderEffect::IsDefaultPropertyAConstraintInput( Property::Index index ) const
354 return DEFAULT_PROPERTY_DETAILS[ index ].constraintInput;
357 Property::Type ShaderEffect::GetDefaultPropertyType(Property::Index index) const
359 if( index < DEFAULT_PROPERTY_COUNT )
361 return DEFAULT_PROPERTY_DETAILS[index].type;
364 // index out of range...return Property::NONE
365 return Property::NONE;
368 void ShaderEffect::SetDefaultProperty( Property::Index index, const Property::Value& propertyValue )
372 case Dali::ShaderEffect::Property::GRID_DENSITY:
374 propertyValue.Get( mGridDensity );
375 if( ( mGeometryHints & Dali::ShaderEffect::HINT_GRID_X ) ||
376 ( mGeometryHints & Dali::ShaderEffect::HINT_GRID_Y ) )
378 //inform all the connected actors
379 for(std::vector< ActorPtr >::iterator it = mConnectedActors.begin(); it != mConnectedActors.end(); ++it )
381 (*it)->RelayoutRequest();
387 case Dali::ShaderEffect::Property::IMAGE:
389 Dali::Image img(Scripting::NewImage( propertyValue ));
392 SetEffectImage( img );
396 DALI_LOG_WARNING("Cannot create image from property value for ShaderEffect image\n");
401 case Dali::ShaderEffect::Property::PROGRAM:
403 std::string vertexPrefix = GetShader("vertexPrefix", propertyValue);
404 std::string fragmentPrefix = GetShader("fragmentPrefix", propertyValue);
405 std::string vertex = GetShader("vertex", propertyValue);
406 std::string fragment = GetShader("fragment", propertyValue);
408 SetPrograms( vertexPrefix, fragmentPrefix, vertex, fragment );
412 case Dali::ShaderEffect::Property::GEOMETRY_HINTS:
414 mGeometryHints = Dali::ShaderEffect::HINT_NONE;
415 std::string s = propertyValue.Get<std::string>();
418 mGeometryHints = Dali::ShaderEffect::HINT_NONE;
420 else if(s == "HINT_GRID_X")
422 mGeometryHints = Dali::ShaderEffect::HINT_GRID_X;
424 else if(s == "HINT_GRID_Y")
426 mGeometryHints = Dali::ShaderEffect::HINT_GRID_Y;
428 else if(s == "HINT_GRID")
430 mGeometryHints = Dali::ShaderEffect::HINT_GRID;
432 else if(s == "HINT_DEPTH_BUFFER")
434 mGeometryHints = Dali::ShaderEffect::HINT_DEPTH_BUFFER;
436 else if(s == "HINT_BLENDING")
438 mGeometryHints = Dali::ShaderEffect::HINT_BLENDING;
440 else if(s == "HINT_DOESNT_MODIFY_GEOMETRY")
442 mGeometryHints = Dali::ShaderEffect::HINT_DOESNT_MODIFY_GEOMETRY;
446 DALI_ASSERT_ALWAYS(!"Geometry hint unknown" );
459 Property::Value ShaderEffect::GetDefaultProperty(Property::Index /*index*/) const
461 // none of our properties are readable so return empty
462 return Property::Value();
465 const SceneGraph::PropertyOwner* ShaderEffect::GetSceneObject() const
470 const PropertyBase* ShaderEffect::GetSceneObjectAnimatableProperty( Property::Index index ) const
472 PropertyMetadata* property = index >= PROPERTY_CUSTOM_START_INDEX ? static_cast<PropertyMetadata*>(FindCustomProperty( index )) : static_cast<PropertyMetadata*>(FindAnimatableProperty( index ));
473 DALI_ASSERT_ALWAYS( property && "Property index is invalid" );
474 return property->GetSceneGraphProperty();
477 const PropertyInputImpl* ShaderEffect::GetSceneObjectInputProperty( Property::Index index ) const
479 return GetSceneObjectAnimatableProperty( index );
482 } // namespace Internal