END_TEST;
}
-int UtcDaliCreateDissolveEffect(void)
+int UtcDaliCreateDissolveEffect( bool highPrecision )
{
ToolkitTestApplication application;
- ShaderEffect effect = Toolkit::CreateDissolveEffect();
- DALI_TEST_CHECK( effect );
+ Property::Map effect = Toolkit::CreateDissolveEffect( highPrecision );
+ DALI_TEST_CHECK( !effect.Empty() );
+
+ Property::Value* customShaderValue = effect.Find( "shader" );
+ DALI_TEST_CHECK( customShaderValue );
+
+ Property::Map customShader;
+ DALI_TEST_CHECK( customShaderValue->Get( customShader ) );
+
+ Property::Value* vertexShaderValue = customShader.Find( "vertex-shader" );
+ DALI_TEST_CHECK( vertexShaderValue );
+
+ std::string vertexShader;
+ DALI_TEST_CHECK( vertexShaderValue->Get( vertexShader ) );
+ DALI_TEST_CHECK( !vertexShader.empty() );
+
+ Property::Value* fragmentShaderValue = customShader.Find( "fragment-shader" );
+ DALI_TEST_CHECK( fragmentShaderValue );
+
+ std::string fragmentShader;
+ DALI_TEST_CHECK( fragmentShaderValue->Get( fragmentShader ) );
+ DALI_TEST_CHECK( !fragmentShader.empty() );
+
+ Property::Value* gridXValue = customShader.Find( "subdivide-grid-x" );
+ DALI_TEST_CHECK( gridXValue );
+
+ int gridX = 0;
+ DALI_TEST_CHECK( gridXValue->Get( gridX ) );
+ DALI_TEST_CHECK( gridX > 1 );
+
+ Property::Value* gridYValue = customShader.Find( "subdivide-grid-y" );
+ DALI_TEST_CHECK( gridYValue );
+
+ int gridY = 0;
+ DALI_TEST_CHECK( gridYValue->Get( gridY ) );
+ DALI_TEST_CHECK( gridY > 1 );
+
+ Property::Value* hintsValue = customShader.Find( "hints" );
+ DALI_TEST_CHECK( hintsValue );
+
+ std::string hints;
+ DALI_TEST_CHECK( hintsValue->Get( hints ) );
+ DALI_TEST_CHECK( hints == "output-is-transparent" );
+
+ Actor actor = Actor::New();
+ Toolkit::DissolveEffectSetCentralLine( actor, Vector2::ONE, Vector2::ONE, 0.0f );
+ DALI_TEST_CHECK( actor.GetPropertyIndex( "uPercentage" ) != Property::INVALID_INDEX );
END_TEST;
}
-int UtcDaliCreateDissolveEffectMediumPrecision(void)
+int UtcDaliCreateDissolveEffectHighPrecision(void)
{
- ToolkitTestApplication application;
-
- ShaderEffect effect = Toolkit::CreateDissolveEffect(false);
- DALI_TEST_CHECK( effect );
+ return UtcDaliCreateDissolveEffect(true);
+}
- END_TEST;
+int UtcDaliCreateDissolveEffectMediumPrecision(void)
+{
+ return UtcDaliCreateDissolveEffect(false);
}
int UtcDaliCreateDissolveLocalEffect(void)
return GetImplementation( *this ).ResetRenderer( renderer, url );
}
+bool RendererFactory::ResetRenderer( ControlRenderer& renderer, const Property::Map& propertyMap )
+{
+ return GetImplementation( *this ).ResetRenderer( renderer, propertyMap );
+}
+
} // namespace Toolkit
} // namespace Dali
*/
bool ResetRenderer( ControlRenderer& renderer, const std::string& url );
+
+ /**
+ * @brief Request the current control renderer from the property map, merging the property map with the renderer
+ *
+ * if the current renderer is capable of merging with the property map the reset the renderer with the merged properties
+ * else the renderer would be a handle to a newly created internal renderer.
+ *
+ * @param[in] propertyMap The map contains the properties required by the control renderer
+ * Depends on the content of the map, different kind of renderer would be returned.
+ * @return Whether a new internal control renderer is created.
+ */
+ bool ResetRenderer( ControlRenderer& renderer, const Property::Map& propertyMap );
+
private:
explicit DALI_INTERNAL RendererFactory(Internal::RendererFactory *impl);
*/
// EXTERNAL INCLUDES
-#include <dali/public-api/shader-effects/shader-effect.h>
+#include <string.h>
+#include <dali/devel-api/rendering/shader.h>
+
+namespace
+{
+ template < typename T>
+ void SafeSetCustomProperty( Dali::Actor& actor, const std::string& name, const T& value )
+ {
+ Dali::Property::Index index = actor.GetPropertyIndex( name );
+ if ( Dali::Property::INVALID_INDEX == index )
+ {
+ index = actor.RegisterProperty( name, value );
+ }
+ else
+ {
+ actor.SetProperty( index, value );
+ }
+ }
+
+ template < typename T>
+ void SafeSetCustomProperty( Dali::Actor& actor, const std::string& name, const T& value, Dali::Property::AccessMode accessMode )
+ {
+ Dali::Property::Index index = actor.GetPropertyIndex( name );
+ if ( Dali::Property::INVALID_INDEX == index )
+ {
+ index = actor.RegisterProperty( name, value, accessMode );
+ }
+ else
+ {
+ actor.SetProperty( index, value );
+ }
+ }
+
+};
namespace Dali
{
* As we use the texture coordinate as pixel position to calculate random offset,
* the line should passing through rectangle {(0,0),(0,1),(1,0),(1,1)},
* so make the position parameter with two component values between 0.0 to 1.0
- * @param[in] dissolveEffect The shader effect
* @param[in] position The point ( locates within rectangle {(0,0),(0,1),(1,0),(1,1)} ) passed through by the central line
* @param[in] displacement The direction of the central line
+ * @param[in] initialProgress, the normalised initial progress of the shader
*/
-inline void DissolveEffectSetCentralLine( ShaderEffect& dissolveEffect, const Vector2& position, const Vector2& displacement )
+inline void DissolveEffectSetCentralLine( Actor& actor, const Vector2& position, const Vector2& displacement, float initialProgress )
{
// the line passes through 'position' and has the direction of 'displacement'
float coefA, coefB, coefC; //line equation: Ax+By+C=0;
rotation = Vector2(-displacement.x, displacement.y);
rotation.Normalize();
- dissolveEffect.SetUniform( "uSaddleParam", saddleParam );
- dissolveEffect.SetUniform( "uTranslation", translation );
- dissolveEffect.SetUniform( "uRotation", rotation );
- dissolveEffect.SetUniform( "uToNext", toNext );
+ SafeSetCustomProperty( actor, "uSaddleParam", saddleParam );
+ SafeSetCustomProperty( actor, "uTranslation", translation );
+ SafeSetCustomProperty( actor, "uRotation", rotation );
+ SafeSetCustomProperty( actor, "uToNext", toNext );
+ SafeSetCustomProperty( actor, "uPercentage", initialProgress, Dali::Property::ANIMATABLE );
}
/**
* @brief Create a new Dissolve effect
* @return A handle to a newly allocated ShaderEffect
*/
-inline ShaderEffect CreateDissolveEffect(bool useHighPrecision = true)
+inline Property::Map CreateDissolveEffect( bool useHighPrecision = true )
{
- std::string prefixHighPrecision( "precision highp float;\n");
- std::string prefixMediumPrecision( "precision mediump float;\n" );
- std::string vertexShader(
- "uniform float uPercentage;\n"
- "uniform vec3 uSaddleParam;\n"
- "uniform vec2 uTranslation;\n"
- "uniform vec2 uRotation; \n"
- "uniform float uToNext;\n"
- "varying float vPercentage;\n"
- "void main()\n"
- "{\n"
- "gl_Position = uProjection * uModelView * vec4(aPosition, 1.0);\n"
- "vTexCoord = aTexCoord;\n"
- //Calculate the distortion value given the dissolve central line
- "vec2 texCoor = vec2( (aTexCoord.s - sTextureRect.s ) / (sTextureRect.p - sTextureRect.s), (aTexCoord.t- sTextureRect.t)/(sTextureRect.q - sTextureRect.t) ); \n"
- "vec2 value = texCoor + uTranslation; \n"
- "mat2 rotateMatrix = mat2( uRotation.s, uRotation.t, -uRotation.t, uRotation.s ); \n"
- "value = rotateMatrix * value; \n"
- "if(uToNext == 1.0) \n"
- " value.s = uSaddleParam[2] + value.s; \n"
- "float delay = value.t*value.t / uSaddleParam[0] - value.s*value.s/uSaddleParam[1];\n"
- "vPercentage = clamp( uPercentage*2.0 - 0.5*sin(delay*1.571) - 0.5, 0.0, 1.0 ); \n"
- "}\n");
- std::string fragmentShader(
- "varying float vPercentage;\n"
- "float rand(vec2 co) \n"
- "{\n"
- " return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453); \n"
- "}\n"
- "void main()\n"
- "{\n"
- //Calculate the randomness
- "float offsetS = rand( vTexCoord * vPercentage ) * (sTextureRect.p - sTextureRect.s) - vTexCoord.s + sTextureRect.s; \n"
- "float offsetT = rand( vec2(vTexCoord.t*vPercentage, vTexCoord.s * vPercentage) ) * (sTextureRect.q - sTextureRect.t) - vTexCoord.t + sTextureRect.t; \n"
- "vec2 lookupCoord = vTexCoord + vec2(offsetS, offsetT) * vPercentage; \n"
- "gl_FragColor = texture2D( sTexture, lookupCoord ) * uColor; \n"
- "gl_FragColor.a *= 1.0 - vPercentage; \n"
- "}" );
-
- // Create the implementation, temporarily owned on stack,
- Dali::ShaderEffect shaderEffect;
- if( useHighPrecision )
- {
- shaderEffect = Dali::ShaderEffect::New(
- prefixHighPrecision+vertexShader, prefixHighPrecision + fragmentShader,
- ShaderEffect::GeometryHints( ShaderEffect::HINT_GRID | ShaderEffect::HINT_BLENDING ) );
- }
- else
- {
- shaderEffect = Dali::ShaderEffect::New(
- prefixMediumPrecision+vertexShader, prefixMediumPrecision + fragmentShader,
- ShaderEffect::GeometryHints( ShaderEffect::HINT_GRID | ShaderEffect::HINT_BLENDING ) );
- }
+ const char* prefixHighPrecision( "precision highp float;\n");
+ const char* prefixMediumPrecision( "precision mediump float;\n" );
+
+ const char* vertexShader( DALI_COMPOSE_SHADER(
+ attribute mediump vec2 aPosition;\n
+ \n
+ uniform mediump mat4 uMvpMatrix;\n
+ uniform vec3 uSize;\n
+ uniform vec4 uTextureRect;
+ \n
+ uniform float uPercentage;\n
+ uniform vec3 uSaddleParam;\n
+ uniform vec2 uTranslation;\n
+ uniform vec2 uRotation; \n
+ uniform float uToNext;\n
+ \n
+ varying float vPercentage;\n
+ varying vec2 vTexCoord;\n
+
+ void main()\n
+ {\n
+ mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);\n
+ vertexPosition.xyz *= uSize;\n
+ vertexPosition = uMvpMatrix * vertexPosition;\n
+ gl_Position = vertexPosition;\n
+
+ vec2 texCoord = aPosition + vec2(0.5);
+ vTexCoord = texCoord;\n
+ //Calculate the distortion value given the dissolve central line
+ vec2 value = texCoord + uTranslation; \n
+ mat2 rotateMatrix = mat2( uRotation.s, uRotation.t, -uRotation.t, uRotation.s ); \n
+ value = rotateMatrix * value; \n
+ if(uToNext == 1.0) \n
+ value.s = uSaddleParam[2] + value.s; \n
+ float delay = value.t*value.t / uSaddleParam[0] - value.s*value.s/uSaddleParam[1];\n
+ vPercentage = clamp( uPercentage*2.0 - 0.5*sin(delay*1.571) - 0.5, 0.0, 1.0 ); \n
+ })
+ );
+
+ const char* fragmentShader( DALI_COMPOSE_SHADER(
+ varying float vPercentage;\n
+ varying mediump vec2 vTexCoord;\n
+ \n
+ uniform sampler2D sTexture;\n
+ uniform lowp vec4 uColor;\n
+ uniform vec4 uTextureRect;
+ \n
+ float rand(vec2 co) \n
+ {\n
+ return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453); \n
+ }\n
+ \n
+ void main()\n
+ {\n
+
+ //Calculate the randomness
+ float offsetS = rand( vTexCoord * vPercentage ) - vTexCoord.s; \n
+ float offsetT = rand( vec2(vTexCoord.t*vPercentage, vTexCoord.s * vPercentage) ) - vTexCoord.t; \n
+ vec2 lookupCoord = vTexCoord + vec2(offsetS, offsetT) * vPercentage; \n
+ gl_FragColor = texture2D( sTexture, lookupCoord ) * uColor; \n
+ gl_FragColor.a *= 1.0 - vPercentage; \n
+ } )
+ );
+
+ Property::Map map;
+
+ Property::Map customShader;
+
+ std::string vertexShaderString;
+ std::string fragmentShaderString;
+ if( useHighPrecision )
+ {
+ vertexShaderString.reserve(strlen( prefixHighPrecision ) + strlen( vertexShader ));
+ vertexShaderString.append( prefixHighPrecision );
+
+ fragmentShaderString.reserve(strlen( prefixHighPrecision ) + strlen( fragmentShader ));
+ fragmentShaderString.append( prefixHighPrecision );
+ }
+ else
+ {
+ vertexShaderString.reserve(strlen( prefixMediumPrecision ) + strlen( vertexShader ));
+ vertexShaderString.append( prefixMediumPrecision );
+
+ fragmentShaderString.reserve(strlen( prefixMediumPrecision ) + strlen( fragmentShader ));
+ fragmentShaderString.append( prefixMediumPrecision );
+ }
+
+ vertexShaderString.append( vertexShader );
+ fragmentShaderString.append( fragmentShader );
- shaderEffect.SetUniform( "uPercentage", 0.0f );
- shaderEffect.SetProperty( ShaderEffect::Property::GRID_DENSITY, Dali::Property::Value(50.0f) );
+ customShader[ "vertex-shader" ] = vertexShaderString;
+ customShader[ "fragment-shader" ] = fragmentShaderString;
- DissolveEffectSetCentralLine( shaderEffect, Vector2(1.0f,0.5f), Vector2(-1.0f, 0.0f) );
+ customShader[ "subdivide-grid-x" ] = 20;
+ customShader[ "subdivide-grid-y" ] = 20;
- return shaderEffect;
+ customShader[ "hints" ] = "output-is-transparent";
+ map[ "shader" ] = customShader;
+ return map;
}
} // namespace Toolkit
void ImageView::SetImage( Property::Map map )
{
- mImage.Reset();
- mUrl.clear();
mPropertyMap = map;
- mRenderer = Toolkit::RendererFactory::Get().GetControlRenderer( mPropertyMap );
+ bool newRendererCreated = false;
+ if( mRenderer )
+ {
+ newRendererCreated = Toolkit::RendererFactory::Get().ResetRenderer( mRenderer, mPropertyMap );
+ }
+ else
+ {
+ mRenderer = Toolkit::RendererFactory::Get().GetControlRenderer( mPropertyMap );
+ newRendererCreated = true;
+ }
//we need to inform any newly created renderers if it is on stage
- if( Self().OnStage() )
+ CustomActor self = Self();
+ if( newRendererCreated && self.OnStage() )
{
- CustomActor self = Self();
mRenderer.SetOnStage( self );
}
{
}
-void BorderRenderer::Initialize( RendererFactoryCache& factoryCache, const Property::Map& propertyMap )
+void BorderRenderer::DoInitialize( RendererFactoryCache& factoryCache, const Property::Map& propertyMap )
{
Initialize( factoryCache );
mBorderSizeIndex = (mImpl->mRenderer).RegisterProperty( SIZE_UNIFORM_NAME, mBorderSize );
}
-void BorderRenderer::CreatePropertyMap( Property::Map& map ) const
+void BorderRenderer::DoCreatePropertyMap( Property::Map& map ) const
{
map.Clear();
map.Insert( RENDERER_TYPE, RENDERER_TYPE_VALUE );
public: // from ControlRenderer
/**
- * @copydoc ControlRenderer::Initialize
+ * @copydoc ControlRenderer::DoInitialize
*/
- virtual void Initialize( RendererFactoryCache& factoryCache, const Property::Map& propertyMap );
+ virtual void DoInitialize( RendererFactoryCache& factoryCache, const Property::Map& propertyMap );
/**
* @copydoc ControlRenderer::SetClipRect
/**
* @copydoc ControlRenderer::CreatePropertyMap
*/
- virtual void CreatePropertyMap( Property::Map& map ) const;
+ virtual void DoCreatePropertyMap( Property::Map& map ) const;
public:
{
}
-void ColorRenderer::Initialize( RendererFactoryCache& factoryCache, const Property::Map& propertyMap )
+void ColorRenderer::DoInitialize( RendererFactoryCache& factoryCache, const Property::Map& propertyMap )
{
Initialize( factoryCache );
//ToDo: renderer applies the offset
}
-void ColorRenderer::CreatePropertyMap( Property::Map& map ) const
+void ColorRenderer::DoCreatePropertyMap( Property::Map& map ) const
{
map.Clear();
map.Insert( RENDERER_TYPE, RENDERER_TYPE_VALUE );
public: // from ControlRenderer
/**
- * @copydoc ControlRenderer::Initialize
+ * @copydoc ControlRenderer::DoInitialize
*/
- virtual void Initialize( RendererFactoryCache& factoryCache, const Property::Map& propertyMap );
+ virtual void DoInitialize( RendererFactoryCache& factoryCache, const Property::Map& propertyMap );
/**
* @copydoc ControlRenderer::SetSize
/**
* @copydoc ControlRenderer::CreatePropertyMap
*/
- virtual void CreatePropertyMap( Property::Map& map ) const;
+ virtual void DoCreatePropertyMap( Property::Map& map ) const;
protected:
/**
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "control-renderer-data-impl.h"
+
+// EXTERNAL HEADER
+#include <dali/public-api/common/dali-common.h>
+#include <dali/integration-api/debug.h>
+#include <dali/public-api/object/property-array.h>
+
+// EXTERNAL HEADER
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+//custom shader
+const char * const CUSTOM_SHADER( "shader" );
+const char * const CUSTOM_VERTEX_SHADER( "vertex-shader" );
+const char * const CUSTOM_FRAGMENT_SHADER( "fragment-shader" );
+const char * const CUSTOM_SUBDIVIDE_GRID_X( "subdivide-grid-x" );
+const char * const CUSTOM_SUBDIVIDE_GRID_Y( "subdivide-grid-y" );
+const char * const CUSTOM_SHADER_HINTS( "hints" ); ///< type STRING for a hint from the below hint strings or an ARRAY of of hint strings
+
+/**
+ * where hints should be contain strings of the following shader hints:
+ * "none" | corresponds to HINT_NONE
+ * "requires-self-depth-test" | corresponds to HINT_REQUIRES_SELF_DEPTH_TEST
+ * "output-is-transparent" | corresponds to HINT_OUTPUT_IS_TRANSPARENT
+ * "output-is-opaque" | corresponds to HINT_OUTPUT_IS_OPAQUE
+ * "modifies-geometry" | corresponds to HINT_MODIFIES_GEOMETRY
+ */
+
+Shader::ShaderHints HintFromString( std::string hintString )
+{
+ if( hintString == "none" )
+ {
+ return Shader::HINT_NONE;
+ }
+ else if( hintString == "requires-self-depth-test" )
+ {
+ return Shader::HINT_REQUIRES_SELF_DEPTH_TEST;
+ }
+ else if( hintString == "output-is-transparent" )
+ {
+ return Shader::HINT_OUTPUT_IS_TRANSPARENT;
+ }
+ else if( hintString == "output-is-opaque" )
+ {
+ return Shader::HINT_OUTPUT_IS_OPAQUE;
+ }
+ else if( hintString == "modifies-geometry" )
+ {
+ return Shader::HINT_MODIFIES_GEOMETRY;
+ }
+ else
+ {
+ DALI_LOG_ERROR( "'%s' hint string is not recognised", hintString.c_str() );
+ }
+
+ return Shader::HINT_NONE;
+}
+
+}// unnamed namespace
+
+Internal::ControlRenderer::Impl::Impl()
+: mCustomShader(NULL),
+ mDepthIndex( 0.0f ),
+ mIsOnStage( false )
+{
+}
+
+Internal::ControlRenderer::Impl::~Impl()
+{
+ delete mCustomShader;
+}
+
+Internal::ControlRenderer::Impl::CustomShader::CustomShader( const Property::Map& map )
+: mGridSize( 1, 1 ),
+ mHints( Shader::HINT_NONE )
+{
+ SetPropertyMap( map );
+}
+
+void Internal::ControlRenderer::Impl::CustomShader::SetPropertyMap( const Property::Map& propertyMap )
+{
+ Property::Value* shaderValue = propertyMap.Find( CUSTOM_SHADER );
+ if( shaderValue )
+ {
+ mVertexShader.clear();
+ mFragmentShader.clear();
+ mGridSize = ImageDimensions( 1, 1 );
+ mHints = Shader::HINT_NONE;
+
+ Property::Map shaderMap;
+ if( shaderValue->Get( shaderMap ) )
+ {
+ Property::Value* vertexShaderValue = shaderMap.Find( CUSTOM_VERTEX_SHADER );
+ if( vertexShaderValue )
+ {
+ if( !vertexShaderValue->Get( mVertexShader ) )
+ {
+ DALI_LOG_ERROR( "'%s' parameter does not correctly specify a string", CUSTOM_VERTEX_SHADER );
+ }
+ }
+
+ Property::Value* fragmentShaderValue = shaderMap.Find( CUSTOM_FRAGMENT_SHADER );
+ if( fragmentShaderValue )
+ {
+ if( !fragmentShaderValue->Get( mFragmentShader ) )
+ {
+ DALI_LOG_ERROR( "'%s' parameter does not correctly specify a string", CUSTOM_FRAGMENT_SHADER );
+ }
+ }
+
+ Property::Value* subdivideXValue = shaderMap.Find( CUSTOM_SUBDIVIDE_GRID_X );
+ if( subdivideXValue )
+ {
+ int subdivideX;
+ if( !subdivideXValue->Get( subdivideX ) || subdivideX < 1 )
+ {
+ DALI_LOG_ERROR( "'%s' parameter does not correctly specify a value greater than 1", CUSTOM_SUBDIVIDE_GRID_X );
+ }
+ else
+ {
+ mGridSize = ImageDimensions( subdivideX, mGridSize.GetY() );
+ }
+ }
+
+ Property::Value* subdivideYValue = shaderMap.Find( CUSTOM_SUBDIVIDE_GRID_Y );
+ if( subdivideYValue )
+ {
+ int subdivideY;
+ if( !subdivideYValue->Get( subdivideY ) || subdivideY < 1 )
+ {
+ DALI_LOG_ERROR( "'%s' parameter does not correctly specify a value greater than 1", CUSTOM_SUBDIVIDE_GRID_Y );
+ }
+ else
+ {
+ mGridSize = ImageDimensions( mGridSize.GetX(), subdivideY );
+ }
+ }
+
+ Property::Value* hintsValue = shaderMap.Find( CUSTOM_SHADER_HINTS );
+ if( hintsValue )
+ {
+ std::string hintString;
+ Property::Array hintsArray;
+
+ if( hintsValue->Get( hintString ) )
+ {
+ mHints = HintFromString( hintString );
+ }
+ else if( hintsValue->Get( hintsArray ) )
+ {
+ int hints = Shader::HINT_NONE;
+ for( Property::Array::SizeType i = 0; i < hintsArray.Count(); ++i)
+ {
+ Property::Value hintValue = hintsArray[ i ];
+ if( hintValue.Get( hintString ) )
+ {
+ hints |= static_cast< int >( HintFromString( hintString ) );
+ }
+ else
+ {
+ DALI_LOG_ERROR( "'%s' parameter does not correctly specify an hint string at index %d", CUSTOM_SHADER_HINTS, i );
+ }
+
+ mHints = static_cast< Shader::ShaderHints >( hints );
+ }
+ }
+ else
+ {
+ DALI_LOG_ERROR( "'%s' parameter does not correctly specify a hint string or an array of hint strings", CUSTOM_SHADER_HINTS );
+ }
+ }
+ }
+ else
+ {
+ //use value with no type to mean reseting the shader back to default
+ if( shaderValue->GetType() != Dali::Property::NONE )
+ {
+ DALI_LOG_ERROR( "'%s' parameter does not correctly specify a property map", CUSTOM_SHADER );
+ }
+ }
+ }
+}
+
+void Internal::ControlRenderer::Impl::CustomShader::CreatePropertyMap( Property::Map& map ) const
+{
+ if( !mVertexShader.empty() || !mFragmentShader.empty() )
+ {
+ Property::Map customShader;
+ if( !mVertexShader.empty() )
+ {
+ customShader.Insert(CUSTOM_VERTEX_SHADER, mVertexShader );
+ }
+ if( !mFragmentShader.empty() )
+ {
+ customShader.Insert(CUSTOM_FRAGMENT_SHADER, mFragmentShader );
+ }
+
+ if( mGridSize.GetWidth() != 1 )
+ {
+ customShader.Insert(CUSTOM_SUBDIVIDE_GRID_X, mGridSize.GetWidth() );
+ }
+ if( mGridSize.GetHeight() != 1 )
+ {
+ customShader.Insert(CUSTOM_SUBDIVIDE_GRID_Y, mGridSize.GetHeight() );
+ }
+
+ if( mHints != Dali::Shader::HINT_NONE )
+ {
+ customShader.Insert(CUSTOM_SHADER_HINTS, static_cast< int >(mHints) );
+ }
+
+ map.Insert( CUSTOM_SHADER, customShader );
+ }
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
*
*/
-// INTERNAL INCLUDES
+// EXTERNAL INCLUDES
#include <dali/public-api/math/vector2.h>
#include <dali/devel-api/rendering/renderer.h>
+#include <dali-toolkit/internal/controls/renderers/control-renderer-impl.h>
+
namespace Dali
{
struct Internal::ControlRenderer::Impl
{
+ struct CustomShader
+ {
+ std::string mVertexShader;
+ std::string mFragmentShader;
+ Dali::ImageDimensions mGridSize;
+ Dali::Shader::ShaderHints mHints; //(bitfield) values from enum Shader::Hints
+
+ CustomShader( const Property::Map& map );
+ void SetPropertyMap( const Property::Map& map );
+ void CreatePropertyMap( Property::Map& map ) const;
+ };
+
Geometry mGeometry;
Shader mShader;
Renderer mRenderer;
+ CustomShader* mCustomShader;
+
Vector2 mSize;
Vector2 mOffset;
Rect<int> mClipRect;
float mDepthIndex;
bool mIsOnStage;
+
+ Impl();
+ ~Impl();
};
} // namespace Internal
// EXTERNAL HEADER
#include <dali/public-api/common/dali-common.h>
+#include <dali/integration-api/debug.h>
//INTERNAL HEARDER
#include <dali-toolkit/internal/controls/renderers/control-renderer-data-impl.h>
+namespace
+{
+//custom shader
+const char * const CUSTOM_SHADER( "shader" );
+const char * const CUSTOM_VERTEX_SHADER( "vertex-shader" );
+const char * const CUSTOM_FRAGMENT_SHADER( "fragment-shader" );
+const char * const CUSTOM_SUBDIVIDE_GRID_X( "subdivide-grid-x" );
+const char * const CUSTOM_SUBDIVIDE_GRID_Y( "subdivide-grid-y" );
+const char * const CUSTOM_SHADER_HINTS( "hints" ); ///< type INTEGER; (bitfield) values from enum Shader::Hints
+}
+
namespace Dali
{
ControlRenderer::ControlRenderer()
: mImpl( new Impl() )
{
- mImpl->mIsOnStage = false;
}
ControlRenderer::~ControlRenderer()
delete mImpl;
}
+void ControlRenderer::Initialize( RendererFactoryCache& factoryCache, const Property::Map& propertyMap )
+{
+ if( mImpl->mCustomShader )
+ {
+ mImpl->mCustomShader->SetPropertyMap( propertyMap );
+ }
+ else
+ {
+ Property::Value* customShaderValue = propertyMap.Find( CUSTOM_SHADER );
+ if( customShaderValue )
+ {
+ Property::Map customShader;
+ if( customShaderValue->Get( customShader ) )
+ {
+ mImpl->mCustomShader = new Impl::CustomShader( propertyMap );
+ }
+ }
+ }
+ DoInitialize( factoryCache, propertyMap );
+}
+
void ControlRenderer::SetSize( const Vector2& size )
{
mImpl->mSize = size;
{
}
+void ControlRenderer::CreatePropertyMap( Property::Map& map ) const
+{
+ if( mImpl->mCustomShader )
+ {
+ mImpl->mCustomShader->CreatePropertyMap( map );
+ }
+ DoCreatePropertyMap( map );
+}
+
} // namespace Internal
} // namespace Toolkit
// EXTERNAL INCLUDES
#include <dali/public-api/object/base-object.h>
+#include <dali/public-api/images/image-operations.h>
+#include <dali/devel-api/rendering/shader.h>
+// INTERNAL INCLUDES
#include <dali-toolkit/devel-api/controls/renderer-factory/renderer-factory.h>
#include <dali-toolkit/devel-api/controls/renderer-factory/control-renderer.h>
* Base class for all Control rendering logic. A control may have multiple control renderers.
*
* Note: The control renderer responds to the the Actor::COLOR by blending it with the 'Multiply' operator.
+ *
+ * The following properties are optional
+ *
+ * | %Property Name | Type |
+ * |---------------------------|------------------|
+ * | custom-shader | MAP |
+ *
+ * where custom-shader is a map with the following properties:
+ * | %Property Name | Type |
+ * |---------------------------|------------------|
+ * | vertex-shader | STRING |
+ * | fragment-shader | STRING |
+ * | subdivide-grid-x | INT |
+ * | subdivide-grid-y | INT |
+ * | shader-hints | INT |
*/
class ControlRenderer : public BaseObject
{
* @param[in] factoryCache A pointer pointing to the RendererFactoryCache object
* @param[in] propertyMap The properties for the requested ControlRenderer object.
*/
- virtual void Initialize( RendererFactoryCache& factoryCache, const Property::Map& propertyMap ) = 0;
+ void Initialize( RendererFactoryCache& factoryCache, const Property::Map& propertyMap );
/**
* @copydoc Toolkit::ControlRenderer::SetSize
/**
* @copydoc Toolkit::ControlRenderer::CreatePropertyMap
*/
- virtual void CreatePropertyMap( Property::Map& map ) const = 0;
+ void CreatePropertyMap( Property::Map& map ) const;
protected:
virtual ~ControlRenderer();
protected:
+ /**
+ * @brief Called by CreatePropertyMap() allowing sub classes to respond to the CreatePropertyMap event
+ *
+ * @param[out] map The renderer property map.
+ */
+ virtual void DoCreatePropertyMap( Property::Map& map ) const = 0;
/**
- * Called by SetOnStage() allowing sub classes to respond to the SetOnStage event
+ * @brief Called by Initialize() allowing sub classes to respond to the Initialize event
+ *
+ * @param[in] factoryCache A pointer pointing to the RendererFactoryCache object
+ * @param[in] propertyMap The properties for the requested ControlRenderer object.
+ */
+ virtual void DoInitialize( RendererFactoryCache& factoryCache, const Property::Map& propertyMap ) = 0;
+
+protected:
+
+ /**
+ * @brief Called by SetOnStage() allowing sub classes to respond to the SetOnStage event
*
* @param[in] actor The actor applying this renderer.
*/
virtual void DoSetOnStage( Actor& actor );
/**
- * Called by SetOffStage() allowing sub classes to respond to the SetOffStage event
+ * @brief Called by SetOffStage() allowing sub classes to respond to the SetOffStage event
*
* @param[in] actor The actor applying this renderer.
*/
ControlRenderer& operator=( const ControlRenderer& renderer );
protected:
-
struct Impl;
Impl* mImpl;
};
{
}
-void GradientRenderer::Initialize( RendererFactoryCache& factoryCache, const Property::Map& propertyMap )
+void GradientRenderer::DoInitialize( RendererFactoryCache& factoryCache, const Property::Map& propertyMap )
{
mImpl->mGeometry = factoryCache.GetGeometry( RendererFactoryCache::QUAD_GEOMETRY );
if( !(mImpl->mGeometry) )
//ToDo: renderer applies the offset
}
-void GradientRenderer::CreatePropertyMap( Property::Map& map ) const
+void GradientRenderer::DoCreatePropertyMap( Property::Map& map ) const
{
map.Clear();
map.Insert( RENDERER_TYPE, RENDERER_TYPE_VALUE );
public: // from ControlRenderer
/**
- * @copydoc ControlRenderer::Initialize
+ * @copydoc ControlRenderer::DoInitialize
*/
- virtual void Initialize( RendererFactoryCache& factoryCache, const Property::Map& propertyMap );
+ virtual void DoInitialize( RendererFactoryCache& factoryCache, const Property::Map& propertyMap );
/**
* @copydoc ControlRenderer::SetSize
/**
* @copydoc ControlRenderer::CreatePropertyMap
*/
- virtual void CreatePropertyMap( Property::Map& map ) const;
+ virtual void DoCreatePropertyMap( Property::Map& map ) const;
protected:
/**
// CLASS HEADER
#include "image-renderer.h"
+// EXTERNAL HEADER
+#include <dali/public-api/images/resource-image.h>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL HEADER
#include <dali-toolkit/internal/controls/renderers/renderer-factory-impl.h>
#include <dali-toolkit/internal/controls/renderers/renderer-factory-cache.h>
#include <dali-toolkit/internal/controls/renderers/control-renderer-impl.h>
#include <dali-toolkit/internal/controls/renderers/control-renderer-data-impl.h>
-#include <dali/public-api/images/resource-image.h>
namespace Dali
{
const char * const RENDERER_TYPE_VALUE("image-renderer");
// property names
-const char * const IMAGE_URL_NAME("image-url");
-const char * const IMAGE_FITTING_MODE("image-fitting-mode");
-const char * const IMAGE_SAMPLING_MODE("image-sampling-mode");
-const char * const IMAGE_DESIRED_WIDTH("image-desired-width");
-const char * const IMAGE_DESIRED_HEIGHT("image-desired-height");
+const char * const IMAGE_URL_NAME( "image-url" );
+const char * const IMAGE_FITTING_MODE( "image-fitting-mode" );
+const char * const IMAGE_SAMPLING_MODE( "image-sampling-mode" );
+const char * const IMAGE_DESIRED_WIDTH( "image-desired-width" );
+const char * const IMAGE_DESIRED_HEIGHT( "image-desired-height" );
// fitting modes
const char * const SHRINK_TO_FIT("shrink-to-fit");
}\n
);
+void AddQuadIndices( Vector< unsigned int >& indices, unsigned int rowIdx, unsigned int nextRowIdx )
+{
+ indices.PushBack( rowIdx );
+ indices.PushBack( nextRowIdx + 1 );
+ indices.PushBack( rowIdx + 1 );
+
+ indices.PushBack( rowIdx );
+ indices.PushBack( nextRowIdx );
+ indices.PushBack( nextRowIdx + 1 );
+}
+
+Geometry GenerateGeometry( const Vector< Vector2 >& vertices, const Vector< unsigned int >& indices )
+{
+ Property::Map vertexFormat;
+ vertexFormat[ "aPosition" ] = Property::VECTOR2;
+ PropertyBuffer vertexPropertyBuffer = PropertyBuffer::New( vertexFormat, vertices.Size() );
+ if( vertices.Size() > 0 )
+ {
+ vertexPropertyBuffer.SetData( &vertices[ 0 ] );
+ }
+
+ Property::Map indexFormat;
+ indexFormat[ "indices" ] = Property::INTEGER;
+ PropertyBuffer indexPropertyBuffer = PropertyBuffer::New( indexFormat, indices.Size() );
+ if( indices.Size() > 0 )
+ {
+ indexPropertyBuffer.SetData( &indices[ 0 ] );
+ }
+
+ // Create the geometry object
+ Geometry geometry = Geometry::New();
+ geometry.AddVertexBuffer( vertexPropertyBuffer );
+ geometry.SetIndexBuffer( indexPropertyBuffer );
+
+ return geometry;
+}
+
+Geometry CreateGeometry( RendererFactoryCache& factoryCache, ImageDimensions gridSize )
+{
+ Geometry geometry;
+
+ if( gridSize == ImageDimensions( 1, 1 ) )
+ {
+ geometry = factoryCache.GetGeometry( RendererFactoryCache::QUAD_GEOMETRY );
+ if( !geometry )
+ {
+ geometry = factoryCache.CreateQuadGeometry();
+ factoryCache.SaveGeometry( RendererFactoryCache::QUAD_GEOMETRY, geometry );
+ }
+ }
+ else
+ {
+ uint16_t gridWidth = gridSize.GetWidth();
+ uint16_t gridHeight = gridSize.GetHeight();
+
+ // Create vertices
+ Vector< Vector2 > vertices;
+ vertices.Reserve( ( gridWidth + 1 ) * ( gridHeight + 1 ) );
+
+ for( int y = 0; y < gridHeight + 1; ++y )
+ {
+ for( int x = 0; x < gridWidth + 1; ++x )
+ {
+ vertices.PushBack( Vector2( (float)x/gridWidth - 0.5f, (float)y/gridHeight - 0.5f) );
+ }
+ }
+
+ // Create indices
+ Vector< unsigned int > indices;
+ indices.Reserve( gridWidth * gridHeight * 6 );
+
+ unsigned int rowIdx = 0;
+ unsigned int nextRowIdx = gridWidth + 1;
+ for( int y = 0; y < gridHeight; ++y, ++nextRowIdx, ++rowIdx )
+ {
+ for( int x = 0; x < gridWidth; ++x, ++nextRowIdx, ++rowIdx )
+ {
+ AddQuadIndices( indices, rowIdx, nextRowIdx );
+ }
+ }
+
+ return GenerateGeometry( vertices, indices );
+ }
+
+ return geometry;
+}
+
} //unnamed namespace
ImageRenderer::ImageRenderer()
{
}
-void ImageRenderer::Initialize( RendererFactoryCache& factoryCache, const Property::Map& propertyMap )
+void ImageRenderer::DoInitialize( RendererFactoryCache& factoryCache, const Property::Map& propertyMap )
{
Initialize(factoryCache);
if( imageURLValue )
{
imageURLValue->Get( mImageUrl );
+ if( !mImageUrl.empty() )
+ {
+ mImage.Reset();
+ }
Property::Value* fittingValue = propertyMap.Find( IMAGE_FITTING_MODE );
if( fittingValue )
mDesiredSize = ImageDimensions( desiredWidth, desiredHeight );
}
-
- mImage.Reset();
}
void ImageRenderer::SetSize( const Vector2& size )
}
}
-void ImageRenderer::CreatePropertyMap( Property::Map& map ) const
+void ImageRenderer::DoCreatePropertyMap( Property::Map& map ) const
{
map.Clear();
map.Insert( RENDERER_TYPE, RENDERER_TYPE_VALUE );
void ImageRenderer::Initialize( RendererFactoryCache& factoryCache )
{
- mImpl->mGeometry = factoryCache.GetGeometry( RendererFactoryCache::QUAD_GEOMETRY );
- if( !(mImpl->mGeometry) )
+ if( !mImpl->mCustomShader )
{
- mImpl->mGeometry = factoryCache.CreateQuadGeometry();
- factoryCache.SaveGeometry( RendererFactoryCache::QUAD_GEOMETRY, mImpl->mGeometry );
- }
+ mImpl->mGeometry = CreateGeometry( factoryCache, ImageDimensions( 1, 1 ) );
+
+ mImpl->mShader = factoryCache.GetShader( RendererFactoryCache::IMAGE_SHADER );
- mImpl->mShader = factoryCache.GetShader( RendererFactoryCache::IMAGE_SHADER );
- if( !mImpl->mShader )
+ if( !mImpl->mShader )
+ {
+ mImpl->mShader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
+ factoryCache.SaveShader( RendererFactoryCache::IMAGE_SHADER, mImpl->mShader );
+ }
+ }
+ else
{
- mImpl->mShader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
- factoryCache.SaveShader( RendererFactoryCache::IMAGE_SHADER, mImpl->mShader );
+ mImpl->mGeometry = CreateGeometry( factoryCache, mImpl->mCustomShader->mGridSize );
+
+ if( mImpl->mCustomShader->mVertexShader.empty() && mImpl->mCustomShader->mFragmentShader.empty() )
+ {
+ mImpl->mShader = factoryCache.GetShader( RendererFactoryCache::IMAGE_SHADER );
+
+ if( !mImpl->mShader )
+ {
+ mImpl->mShader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
+ factoryCache.SaveShader( RendererFactoryCache::IMAGE_SHADER, mImpl->mShader );
+ }
+ }
+ else
+ {
+ mImpl->mShader = Shader::New( mImpl->mCustomShader->mVertexShader.empty() ? VERTEX_SHADER : mImpl->mCustomShader->mVertexShader,
+ mImpl->mCustomShader->mFragmentShader.empty() ? FRAGMENT_SHADER : mImpl->mCustomShader->mFragmentShader,
+ mImpl->mCustomShader->mHints );
+ }
}
- mDesiredSize = ImageDimensions();
- mFittingMode = FittingMode::DEFAULT;
- mSamplingMode = SamplingMode::DEFAULT;
- mImageUrl.clear();
+ if( mImpl->mRenderer )
+ {
+ mImpl->mRenderer.SetGeometry( mImpl->mGeometry );
+ Material material = mImpl->mRenderer.GetMaterial();
+ if( material )
+ {
+ material.SetShader( mImpl->mShader );
+ }
+ }
}
void ImageRenderer::SetImage( const std::string& imageUrl )
public: // from ControlRenderer
/**
- * @copydoc ControlRenderer::Initialize
+ * @copydoc ControlRenderer::DoInitialize
*/
- virtual void Initialize( RendererFactoryCache& factoryCache, const Property::Map& propertyMap );
+ virtual void DoInitialize( RendererFactoryCache& factoryCache, const Property::Map& propertyMap );
/**
* @copydoc ControlRenderer::SetSize
/**
* @copydoc ControlRenderer::CreatePropertyMap
*/
- virtual void CreatePropertyMap( Property::Map& map ) const;
+ virtual void DoCreatePropertyMap( Property::Map& map ) const;
protected:
/**
{
}
-void NPatchRenderer::Initialize( RendererFactoryCache& factoryCache, const Property::Map& propertyMap )
+void NPatchRenderer::DoInitialize( RendererFactoryCache& factoryCache, const Property::Map& propertyMap )
{
Initialize(factoryCache);
mCroppedImage.Reset();
}
-void NPatchRenderer::CreatePropertyMap( Property::Map& map ) const
+void NPatchRenderer::DoCreatePropertyMap( Property::Map& map ) const
{
map.Clear();
map.Insert( RENDERER_TYPE, RENDERER_TYPE_VALUE );
public: // from ControlRenderer
/**
- * @copydoc ControlRenderer::Initialize
+ * @copydoc ControlRenderer::DoInitialize
*/
- virtual void Initialize( RendererFactoryCache& factoryCache, const Property::Map& propertyMap );
+ virtual void DoInitialize( RendererFactoryCache& factoryCache, const Property::Map& propertyMap );
/**
* @copydoc ControlRenderer::GetNaturalSize
/**
* @copydoc ControlRenderer::CreatePropertyMap
*/
- virtual void CreatePropertyMap( Property::Map& map ) const;
+ virtual void DoCreatePropertyMap( Property::Map& map ) const;
protected:
/**
}
}
+bool RendererFactory::ResetRenderer( Toolkit::ControlRenderer& renderer, const Property::Map& propertyMap )
+{
+ Property::Value* type = propertyMap.Find( RENDERER_TYPE_NAME );
+ std::string typeValue ;
+ if( type && type->Get( typeValue ))
+ {
+ //If there's been a renderer type change then we have to return a new shader
+ if( typeValue == COLOR_RENDERER && typeid( renderer ) != typeid( ColorRenderer ) )
+ {
+ renderer = GetControlRenderer( propertyMap );
+ return true;
+ }
+ else if( typeValue == GRADIENT_RENDERER && typeid( renderer ) != typeid( GradientRenderer ) )
+ {
+ renderer = GetControlRenderer( propertyMap );
+ return true;
+ }
+ else if( typeValue == IMAGE_RENDERER && typeid( renderer ) != typeid( ImageRenderer ) )
+ {
+ renderer = GetControlRenderer( propertyMap );
+ return true;
+ }
+ else if( typeValue == N_PATCH_RENDERER && typeid( renderer ) != typeid( NPatchRenderer ) )
+ {
+ renderer = GetControlRenderer( propertyMap );
+ return true;
+ }
+ else if( typeValue == BORDER_RENDERER && typeid( renderer ) != typeid( BorderRenderer ) )
+ {
+ renderer = GetControlRenderer( propertyMap );
+ return true;
+ }
+ }
+
+ if( !mFactoryCache )
+ {
+ mFactoryCache = new RendererFactoryCache();
+ }
+ GetImplementation( renderer ).Initialize( *( mFactoryCache.Get() ), propertyMap );
+ return false;
+}
+
} // namespace Internal
} // namespace Toolkit
/**
* @copydoc Toolkit::RenderFactory::GetControlRenderer( const Property::Map& )
*/
- Toolkit::ControlRenderer GetControlRenderer( const Property::Map& propertyMap );
+ Toolkit::ControlRenderer GetControlRenderer( const Property::Map& propertyMap );
+
+ /**
+ * @copydoc Toolkit::RenderFactory::ResetRenderer( Toolkit::ControlRenderer& renderer, const Property::Map& propertyMap )
+ */
+ bool ResetRenderer( Toolkit::ControlRenderer& renderer, const Property::Map& propertyMap );
/**
* @copydoc Toolkit::RenderFactory::GetControlRenderer( const Vector4& )
$(toolkit_src_dir)/builder/tree-node-manipulator.cpp \
$(toolkit_src_dir)/builder/replacement.cpp \
$(toolkit_src_dir)/controls/renderers/control-renderer-impl.cpp \
+ $(toolkit_src_dir)/controls/renderers/control-renderer-data-impl.cpp \
$(toolkit_src_dir)/controls/renderers/renderer-factory-cache.cpp \
$(toolkit_src_dir)/controls/renderers/renderer-factory-impl.cpp \
$(toolkit_src_dir)/controls/renderers/border/border-renderer.cpp \