[dali_2.3.23] Merge branch 'devel/master'
[platform/core/uifw/dali-demo.git] / examples / contact-cards / clipped-image.cpp
1 /*
2  * Copyright (c) 2021 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  *
16  */
17
18 // HEADER
19 #include "clipped-image.h"
20
21 // EXTERNAL INCLUDES
22 #include <dali-toolkit/dali-toolkit.h>
23
24 // INTERNAL INCLUDES
25 #include "generated/clipped-image-frag.h"
26 #include "generated/clipped-image-vert.h"
27
28 namespace ClippedImage
29 {
30 using namespace Dali;
31 using namespace Dali::Toolkit;
32
33 namespace
34 {
35 const char* const DELTA_PROPERTY_NAME("uDelta"); ///< Name of uniform used to mix the Circle and Quad geometries.
36
37 /**
38  * @brief Creates the shader required for the clipped image
39  * @return A reference to a static handle to a shader object (only created when first called).
40  */
41 Shader& CreateShader()
42 {
43   // Only need to create it once
44   // The issue with using a static is that the shader will only get destroyed at application destruction.
45   // This is OK for a simple use cases such as this example, but for more polished applications, the shader creation/destruction needs to
46   // be managed by the application writer.
47   static Shader shader;
48
49   if(!shader)
50   {
51     shader = Shader::New(SHADER_CLIPPED_IMAGE_VERT, SHADER_CLIPPED_IMAGE_FRAG);
52   }
53
54   return shader;
55 }
56
57 /**
58  * @brief Creates the geometry required for the clipped image
59  * @return A reference to a static handle to a geometry object (only created when first called).
60  */
61 Geometry& CreateGeometry()
62 {
63   // Only need to create it once
64   // The issue with using a static is that the geometry will only get destroyed at application destruction.
65   // This is OK for a simple use cases such as this example, but for more polished applications, the geometry creation/destruction needs to
66   // be managed by the application writer.
67   static Geometry geometry;
68
69   if(!geometry)
70   {
71     const int vertexCount = 34; // Needs to be 4n plus 2 where n is a positive integer above 4
72
73     // Create the circle geometry
74
75     // Radius is bound to actor's dimensions so this should not be increased.
76     // If a bigger circle is required then the actor size should be increased.
77     const float   radius = 0.5f;
78     const Vector2 center = Vector2::ZERO;
79
80     // Create a buffer for vertex data
81     Vector2 circleBuffer[vertexCount];
82     int     idx = 0;
83
84     // Center vertex for triangle fan
85     circleBuffer[idx++] = center;
86
87     // Outer vertices of the circle
88     const int outerVertexCount = vertexCount - 1;
89
90     for(int i = 0; i < outerVertexCount; ++i)
91     {
92       const float percent = (i / static_cast<float>(outerVertexCount - 1));
93       const float rad     = percent * 2.0f * Math::PI;
94
95       // Vertex position
96       Vector2 outer;
97       outer.x = center.x + radius * cos(rad);
98       outer.y = center.y + radius * sin(rad);
99
100       circleBuffer[idx++] = outer;
101     }
102
103     Property::Map circleVertexFormat;
104     circleVertexFormat["aPositionCircle"] = Property::VECTOR2;
105     VertexBuffer circleVertices           = VertexBuffer::New(circleVertexFormat);
106     circleVertices.SetData(circleBuffer, vertexCount);
107
108     // Create the Quad Geometry
109     Vector2 quadBuffer[vertexCount];
110     idx               = 0;
111     quadBuffer[idx++] = center;
112
113     const size_t vertsPerSide = (vertexCount - 2) / 4;
114     Vector2      outer(0.5f, 0.0f);
115     quadBuffer[idx++]        = outer;
116     float incrementPerBuffer = 1.0f / static_cast<float>(vertsPerSide);
117
118     for(size_t i = 0; i < vertsPerSide && outer.y < 0.5f; ++i)
119     {
120       outer.y += incrementPerBuffer;
121       quadBuffer[idx++] = outer;
122     }
123
124     for(size_t i = 0; i < vertsPerSide && outer.x > -0.5f; ++i)
125     {
126       outer.x -= incrementPerBuffer;
127       quadBuffer[idx++] = outer;
128     }
129
130     for(size_t i = 0; i < vertsPerSide && outer.y > -0.5f; ++i)
131     {
132       outer.y -= incrementPerBuffer;
133       quadBuffer[idx++] = outer;
134     }
135
136     for(size_t i = 0; i < vertsPerSide && outer.x < 0.5f; ++i)
137     {
138       outer.x += incrementPerBuffer;
139       quadBuffer[idx++] = outer;
140     }
141
142     for(size_t i = 0; i < vertsPerSide && outer.y < 0.0f; ++i)
143     {
144       outer.y += incrementPerBuffer;
145       quadBuffer[idx++] = outer;
146     }
147
148     Property::Map vertexFormat;
149     vertexFormat["aPositionQuad"] = Property::VECTOR2;
150     VertexBuffer quadVertices2    = VertexBuffer::New(vertexFormat);
151     quadVertices2.SetData(quadBuffer, vertexCount);
152
153     // Create the geometry object itself
154     geometry = Geometry::New();
155     geometry.AddVertexBuffer(circleVertices);
156     geometry.AddVertexBuffer(quadVertices2);
157     geometry.SetType(Geometry::TRIANGLE_FAN);
158   }
159
160   return geometry;
161 }
162
163 } // unnamed namespace
164
165 const float CIRCLE_GEOMETRY = 0.0f;
166 const float QUAD_GEOMETRY   = 1.0f;
167
168 Dali::Toolkit::Control Create(const std::string& imagePath, Property::Index& propertyIndex)
169 {
170   // Create a control which whose geometry will be morphed between a circle and a quad
171   Control clippedImage = Control::New();
172   clippedImage.SetProperty(Actor::Property::CLIPPING_MODE, ClippingMode::CLIP_CHILDREN);
173
174   // Create the required renderer and add to the clipped image control
175   Renderer renderer = Renderer::New(CreateGeometry(), CreateShader());
176   renderer.SetProperty(Renderer::Property::BLEND_MODE, BlendMode::ON);
177   clippedImage.AddRenderer(renderer);
178
179   // Register the property on the clipped image control which will allow animations between a circle and a quad
180   propertyIndex = clippedImage.RegisterProperty(DELTA_PROPERTY_NAME, 0.0f);
181
182   // Add the actual image to the control
183   Control image = ImageView::New(imagePath);
184   image.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS);
185   image.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
186   image.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
187   clippedImage.Add(image);
188
189   return clippedImage;
190 }
191
192 } // namespace ClippedImage