2 * Copyright (c) 2016 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 "clipped-image.h"
22 #include <dali-toolkit/dali-toolkit.h>
24 namespace ClippedImage
28 using namespace Dali::Toolkit;
33 const char * const DELTA_PROPERTY_NAME( "uDelta" ); ///< Name of uniform used to mix the Circle and Quad geometries.
36 * @brief This vertex-shader mixes in the quad and circle geometry depending on the value of uDelta.
38 * uDelta is used to mix in the Circle and the Quad positions.
39 * If uDelta is 0.0f, then the circle position is adopted and if it is 1.0f, then the quad position is adopted.
41 const char * VERTEX_SHADER = DALI_COMPOSE_SHADER(
42 attribute mediump vec2 aPositionCircle;\n
43 attribute mediump vec2 aPositionQuad;\n
44 uniform mediump float uDelta;
45 uniform mediump mat4 uMvpMatrix;\n
46 uniform mediump vec3 uSize;\n
50 mediump vec4 vertexPosition = vec4(mix(aPositionCircle,aPositionQuad,uDelta), 0.0, 1.0);\n
51 vertexPosition.xyz *= uSize;\n
52 gl_Position = uMvpMatrix * vertexPosition;\n
57 * @brief This fragment-shader does not output anything. It's for a control which is just going to clip as specified in the vertex shader.
59 const char * FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
62 gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0);\n
67 * @brief Creates the shader required for the clipped image
68 * @return A reference to a static handle to a shader object (only created when first called).
70 Shader& CreateShader()
72 // Only need to create it once
73 // The issue with using a static is that the shader will only get destroyed at application destruction.
74 // This is OK for a simple use cases such as this example, but for more polished applications, the shader creation/destruction needs to
75 // be managed by the application writer.
80 shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
87 * @brief Creates the geometry required for the clipped image
88 * @return A reference to a static handle to a geometry object (only created when first called).
90 Geometry& CreateGeometry()
92 // Only need to create it once
93 // The issue with using a static is that the geometry will only get destroyed at application destruction.
94 // This is OK for a simple use cases such as this example, but for more polished applications, the geometry creation/destruction needs to
95 // be managed by the application writer.
96 static Geometry geometry;
100 const int vertexCount = 34; // Needs to be 4n plus 2 where n is a positive integer above 4
102 // Create the circle geometry
104 // Radius is bound to actor's dimensions so this should not be increased.
105 // If a bigger circle is required then the actor size should be increased.
106 const float radius = 0.5f;
107 const Vector2 center = Vector2::ZERO;
109 // Create a buffer for vertex data
110 Vector2 circleBuffer[vertexCount];
113 // Center vertex for triangle fan
114 circleBuffer[ idx++ ] = center;
116 // Outer vertices of the circle
117 const int outerVertexCount = vertexCount - 1;
119 for ( int i = 0; i < outerVertexCount; ++i )
121 const float percent = ( i / static_cast< float >( outerVertexCount - 1 ) );
122 const float rad = percent * 2.0f * Math::PI;
126 outer.x = center.x + radius * cos( rad );
127 outer.y = center.y + radius * sin( rad );
129 circleBuffer[ idx++ ] = outer;
132 Property::Map circleVertexFormat;
133 circleVertexFormat["aPositionCircle"] = Property::VECTOR2;
134 PropertyBuffer circleVertices = PropertyBuffer::New( circleVertexFormat );
135 circleVertices.SetData( circleBuffer, vertexCount );
137 // Create the Quad Geometry
138 Vector2 quadBuffer[vertexCount];
140 quadBuffer[ idx++ ] = center;
142 const size_t vertsPerSide = ( vertexCount - 2 ) / 4;
143 Vector2 outer( 0.5f, 0.0f );
144 quadBuffer[ idx++ ] = outer;
145 float incrementPerBuffer = 1.0f / static_cast< float >( vertsPerSide );
147 for( size_t i = 0; i < vertsPerSide && outer.y < 0.5f; ++i )
149 outer.y += incrementPerBuffer;
150 quadBuffer[ idx++ ] = outer;
153 for( size_t i = 0; i < vertsPerSide && outer.x > -0.5f; ++i )
155 outer.x -= incrementPerBuffer;
156 quadBuffer[ idx++ ] = outer;
159 for( size_t i = 0; i < vertsPerSide && outer.y > -0.5f; ++i )
161 outer.y -= incrementPerBuffer;
162 quadBuffer[ idx++ ] = outer;
165 for( size_t i = 0; i < vertsPerSide && outer.x < 0.5f; ++i )
167 outer.x += incrementPerBuffer;
168 quadBuffer[ idx++ ] = outer;
171 for( size_t i = 0; i < vertsPerSide && outer.y < 0.0f; ++i )
173 outer.y += incrementPerBuffer;
174 quadBuffer[ idx++ ] = outer;
177 Property::Map vertexFormat;
178 vertexFormat["aPositionQuad"] = Property::VECTOR2;
179 PropertyBuffer quadVertices2 = PropertyBuffer::New( vertexFormat );
180 quadVertices2.SetData( quadBuffer, vertexCount );
182 // Create the geometry object itself
183 geometry = Geometry::New();
184 geometry.AddVertexBuffer( circleVertices );
185 geometry.AddVertexBuffer( quadVertices2 );
186 geometry.SetType( Geometry::TRIANGLE_FAN );
192 } // unnamed namespace
194 const float CIRCLE_GEOMETRY = 0.0f;
195 const float QUAD_GEOMETRY = 1.0f;
197 Dali::Toolkit::Control Create( const std::string& imagePath, Property::Index& propertyIndex )
199 // Create a control which whose geometry will be morphed between a circle and a quad
200 Control clippedImage = Control::New();
201 clippedImage.SetProperty( Actor::Property::CLIPPING_MODE, ClippingMode::CLIP_CHILDREN );
203 // Create the required renderer and add to the clipped image control
204 Renderer renderer = Renderer::New( CreateGeometry(), CreateShader() );
205 renderer.SetProperty( Renderer::Property::BLEND_MODE, BlendMode::ON );
206 clippedImage.AddRenderer( renderer );
208 // Register the property on the clipped image control which will allow animations between a circle and a quad
209 propertyIndex = clippedImage.RegisterProperty( DELTA_PROPERTY_NAME, 0.0f );
211 // Add the actual image to the control
212 Control image = ImageView::New( imagePath );
213 image.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
214 image.SetParentOrigin( ParentOrigin::CENTER );
215 image.SetAnchorPoint( AnchorPoint::CENTER );
216 clippedImage.Add( image );
221 } // namespace ClippedImage