fad71e004d1c5eddd8cf1cd33c0f646635065d53
[platform/core/uifw/dali-demo.git] / examples / contact-cards / clipped-image.cpp
1 /*
2  * Copyright (c) 2016 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 namespace ClippedImage
25 {
26
27 using namespace Dali;
28 using namespace Dali::Toolkit;
29
30 namespace
31 {
32
33 const char * const DELTA_PROPERTY_NAME( "uDelta" ); ///< Name of uniform used to mix the Circle and Quad geometries.
34
35 /**
36  * @brief This vertex-shader mixes in the quad and circle geometry depending on the value of uDelta.
37  *
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.
40  */
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
47   \n
48   void main()\n
49   {\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
53   }\n
54 );
55
56 /**
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.
58  */
59 const char * FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
60   void main()\n
61   {\n
62     gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0);\n
63   }\n
64 );
65
66 /**
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).
69  */
70 Shader& CreateShader()
71 {
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.
76   static Shader shader;
77
78   if( !shader )
79   {
80     shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
81   }
82
83   return shader;
84 }
85
86 /**
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).
89  */
90 Geometry& CreateGeometry()
91 {
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;
97
98   if ( !geometry )
99   {
100     const int vertexCount = 34; // Needs to be 4n plus 2 where n is a positive integer above 4
101
102     // Create the circle geometry
103
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;
108
109     // Create a buffer for vertex data
110     Vector2 circleBuffer[vertexCount];
111     int idx = 0;
112
113     // Center vertex for triangle fan
114     circleBuffer[ idx++ ] = center;
115
116     // Outer vertices of the circle
117     const int outerVertexCount = vertexCount - 1;
118
119     for ( int i = 0; i < outerVertexCount; ++i )
120     {
121       const float percent = ( i / static_cast< float >( outerVertexCount - 1 ) );
122       const float rad = percent * 2.0f * Math::PI;
123
124       // Vertex position
125       Vector2 outer;
126       outer.x = center.x + radius * cos( rad );
127       outer.y = center.y + radius * sin( rad );
128
129       circleBuffer[ idx++ ] = outer;
130     }
131
132     Property::Map circleVertexFormat;
133     circleVertexFormat["aPositionCircle"] = Property::VECTOR2;
134     VertexBuffer circleVertices = VertexBuffer::New( circleVertexFormat );
135     circleVertices.SetData( circleBuffer, vertexCount );
136
137     // Create the Quad Geometry
138     Vector2 quadBuffer[vertexCount];
139     idx = 0;
140     quadBuffer[ idx++ ]  = center;
141
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 );
146
147     for( size_t i = 0; i < vertsPerSide && outer.y < 0.5f; ++i )
148     {
149       outer.y += incrementPerBuffer;
150       quadBuffer[ idx++ ] = outer;
151     }
152
153     for( size_t i = 0; i < vertsPerSide && outer.x > -0.5f; ++i )
154     {
155       outer.x -= incrementPerBuffer;
156       quadBuffer[ idx++ ] = outer;
157     }
158
159     for( size_t i = 0; i < vertsPerSide && outer.y > -0.5f; ++i )
160     {
161       outer.y -= incrementPerBuffer;
162       quadBuffer[ idx++ ] = outer;
163     }
164
165     for( size_t i = 0; i < vertsPerSide && outer.x < 0.5f; ++i )
166     {
167       outer.x += incrementPerBuffer;
168       quadBuffer[ idx++ ] = outer;
169     }
170
171     for( size_t i = 0; i < vertsPerSide && outer.y < 0.0f; ++i )
172     {
173       outer.y += incrementPerBuffer;
174       quadBuffer[ idx++ ] = outer;
175     }
176
177     Property::Map vertexFormat;
178     vertexFormat["aPositionQuad"] = Property::VECTOR2;
179     VertexBuffer quadVertices2 = VertexBuffer::New( vertexFormat );
180     quadVertices2.SetData( quadBuffer, vertexCount );
181
182     // Create the geometry object itself
183     geometry = Geometry::New();
184     geometry.AddVertexBuffer( circleVertices );
185     geometry.AddVertexBuffer( quadVertices2 );
186     geometry.SetType( Geometry::TRIANGLE_FAN );
187   }
188
189   return geometry;
190 }
191
192 } // unnamed namespace
193
194 const float CIRCLE_GEOMETRY = 0.0f;
195 const float QUAD_GEOMETRY = 1.0f;
196
197 Dali::Toolkit::Control Create( const std::string& imagePath, Property::Index& propertyIndex )
198 {
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 );
202
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 );
207
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 );
210
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 );
217
218   return clippedImage;
219 }
220
221 } // namespace ClippedImage