2 * Copyright (c) 2020 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
27 using namespace Dali::Toolkit;
31 const char* const DELTA_PROPERTY_NAME("uDelta"); ///< Name of uniform used to mix the Circle and Quad geometries.
34 * @brief This vertex-shader mixes in the quad and circle geometry depending on the value of uDelta.
36 * uDelta is used to mix in the Circle and the Quad positions.
37 * If uDelta is 0.0f, then the circle position is adopted and if it is 1.0f, then the quad position is adopted.
40 const char * VERTEX_SHADER = DALI_COMPOSE_SHADER(
41 attribute mediump vec2 aPositionCircle;\n
42 attribute mediump vec2 aPositionQuad;\n
43 uniform mediump float uDelta;
44 uniform mediump mat4 uMvpMatrix;\n
45 uniform mediump vec3 uSize;\n
49 mediump vec4 vertexPosition = vec4(mix(aPositionCircle,aPositionQuad,uDelta), 0.0, 1.0);\n
50 vertexPosition.xyz *= uSize;\n
51 gl_Position = uMvpMatrix * vertexPosition;\n
56 * @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.
58 const char * FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
61 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 VertexBuffer circleVertices = VertexBuffer::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 VertexBuffer quadVertices2 = VertexBuffer::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.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
215 image.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
216 clippedImage.Add(image);
221 } // namespace ClippedImage