DALi Version 1.4.27
[platform/core/uifw/dali-demo.git] / examples / simple-text-renderer / simple-text-renderer-example.cpp
1 /*
2  * Copyright (c) 2019 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 /**
19  * @file simple-text-renderer-example.cpp
20  * @brief Basic usage of Text Renderer utility.
21  */
22
23 // EXTERNAL INCLUDES
24 #include <dali/devel-api/adaptor-framework/pixel-buffer.h>
25 #include <dali-toolkit/dali-toolkit.h>
26 #include <dali-toolkit/devel-api/text/text-utils-devel.h>
27 #include <devel-api/adaptor-framework/image-loading.h>
28
29 #include <iostream>
30 #include <fstream>
31
32 using namespace std;
33 using namespace Dali;
34 using namespace Dali::Toolkit;
35
36 namespace
37 {
38
39 const std::string IMAGE1 = DEMO_IMAGE_DIR "application-icon-1.png";
40 const std::string IMAGE2 = DEMO_IMAGE_DIR "application-icon-6.png";
41
42 #define MAKE_SHADER(A)#A
43
44 const std::string VERSION_3_ES = "#version 300 es\n";
45
46 const char* VERTEX_SHADER = MAKE_SHADER(
47   precision mediump float;
48
49   in vec2 aPosition;
50   in vec2 aTexCoord;
51
52   out vec2 vUV;
53
54   uniform vec3 uSize;
55   uniform mat4 uMvpMatrix;
56
57   void main()
58   {
59     vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);
60     vertexPosition.xyz *= uSize;
61     gl_Position = uMvpMatrix * vertexPosition;
62
63     vUV = aTexCoord;
64   }
65 );
66
67 const char* FRAGMENT_SHADER = MAKE_SHADER(
68   precision mediump float;
69
70   in vec2 vUV;
71
72   out vec4 FragColor;
73
74   uniform sampler2D sAlbedo;
75   uniform vec4 uColor;
76
77   void main()
78   {
79     vec4 color = texture( sAlbedo, vUV );
80     FragColor = vec4( color.rgb, uColor.a * color.a );
81   }
82 );
83
84 Renderer CreateRenderer()
85 {
86   // Create the geometry.
87   struct Vertex
88   {
89     Dali::Vector2 position;
90     Dali::Vector2 texCoord;
91   };
92
93   static const Vertex vertices[] = {{ Dali::Vector2( -0.5f, -0.5f ), Dali::Vector2( 0.0f, 0.0f ) },
94                                     { Dali::Vector2(  0.5f, -0.5f ), Dali::Vector2( 1.0f, 0.0f ) },
95                                     { Dali::Vector2( -0.5f,  0.5f ), Dali::Vector2( 0.0f, 1.0f ) },
96                                     { Dali::Vector2(  0.5f,  0.5f ), Dali::Vector2( 1.0f, 1.0f ) }};
97
98   Property::Map property;
99   property.Add("aPosition", Property::VECTOR2).Add("aTexCoord", Property::VECTOR2);
100
101   PropertyBuffer vertexBuffer = PropertyBuffer::New(property);
102
103   vertexBuffer.SetData(vertices, sizeof(vertices) / sizeof(Vertex));
104
105   Geometry geometry = Geometry::New();
106   geometry.AddVertexBuffer(vertexBuffer);
107
108   geometry.SetType(Geometry::TRIANGLE_STRIP);
109
110   // Create the shader
111   Shader shader = Shader::New( VERSION_3_ES + VERTEX_SHADER, VERSION_3_ES + FRAGMENT_SHADER );
112
113   // Create the renderer
114
115   Renderer renderer = Renderer::New( geometry, shader );
116
117   return renderer;
118 }
119
120 TextureSet CreateTextureSet( const Dali::Toolkit::DevelText::RendererParameters& textParameters, const std::vector<std::string>& embeddedItems )
121 {
122
123   Dali::Vector<Dali::Toolkit::DevelText::EmbeddedItemInfo> embeddedItemLayout;
124
125   Devel::PixelBuffer pixelBuffer = Toolkit::DevelText::Render( textParameters, embeddedItemLayout );
126
127
128   const int dstWidth = static_cast<int>( pixelBuffer.GetWidth() );
129   const int dstHeight = static_cast<int>( pixelBuffer.GetHeight() );
130
131   unsigned int index = 0u;
132   for( const auto& itemLayout : embeddedItemLayout )
133   {
134     int width = static_cast<int>( itemLayout.size.width );
135     int height = static_cast<int>( itemLayout.size.height );
136     int x = static_cast<int>( itemLayout.position.x );
137     int y = static_cast<int>( itemLayout.position.y );
138
139     Dali::Devel::PixelBuffer itemPixelBuffer = Dali::LoadImageFromFile( embeddedItems[index++] );
140     itemPixelBuffer.Resize( width, height );
141     itemPixelBuffer.Rotate( itemLayout.angle );
142
143     width = static_cast<int>( itemPixelBuffer.GetWidth() );
144     height = static_cast<int>( itemPixelBuffer.GetHeight() );
145
146     Dali::Pixel::Format itemPixelFormat = itemPixelBuffer.GetPixelFormat();
147
148     // Check if the item is out of the buffer.
149
150     if( ( x + width < 0 ) ||
151         ( x > dstWidth ) ||
152         ( y < 0 ) ||
153         ( y - height > dstHeight ) )
154     {
155       // The embedded item is completely out of the buffer.
156       continue;
157     }
158
159     // Crop if it exceeds the boundaries of the destination buffer.
160     int layoutX = 0;
161     int layoutY = 0;
162     int cropX = 0;
163     int cropY = 0;
164     int newWidth = width;
165     int newHeight = height;
166
167     bool crop = false;
168
169     if( 0 > x )
170     {
171       newWidth += x;
172       cropX = std::abs( x );
173       crop = true;
174     }
175     else
176     {
177       layoutX = x;
178     }
179
180     if( cropX + newWidth > dstWidth )
181     {
182       crop = true;
183       newWidth -= ( ( cropX + newWidth ) - dstWidth );
184     }
185
186     layoutY = y;
187     if( 0.f > layoutY )
188     {
189       newHeight += layoutY;
190       cropY = std::abs(layoutY);
191       crop = true;
192     }
193
194     if( cropY + newHeight > dstHeight )
195     {
196       crop = true;
197       newHeight -= ( ( cropY + newHeight ) - dstHeight );
198     }
199
200     uint16_t uiCropX = static_cast<uint16_t>(cropX);
201     uint16_t uiCropY = static_cast<uint16_t>(cropY);
202     uint16_t uiNewWidth = static_cast<uint16_t>(newWidth);
203     uint16_t uiNewHeight = static_cast<uint16_t>(newHeight);
204
205     if( crop )
206     {
207       itemPixelBuffer.Crop( uiCropX, uiCropY, uiNewWidth, uiNewHeight );
208     }
209
210     // Blend the item pixel buffer with the text's color according its blending mode.
211     if( Dali::TextAbstraction::ColorBlendingMode::MULTIPLY == itemLayout.colorBlendingMode )
212     {
213       Dali::Devel::PixelBuffer buffer = Dali::Devel::PixelBuffer::New( uiNewWidth,
214                                                                        uiNewHeight,
215                                                                        itemPixelFormat );
216
217       unsigned char* bufferPtr = buffer.GetBuffer();
218       const unsigned char* itemBufferPtr = itemPixelBuffer.GetBuffer();
219       const unsigned int bytesPerPixel = Dali::Pixel::GetBytesPerPixel(itemPixelFormat);
220       const unsigned int size = uiNewWidth * uiNewHeight * bytesPerPixel;
221
222       for (unsigned int i = 0u; i < size; i += bytesPerPixel)
223       {
224         *(bufferPtr + 0u) = static_cast<unsigned char>( static_cast<float>( *(itemBufferPtr + 0u) ) * textParameters.textColor.r );
225         *(bufferPtr + 1u) = static_cast<unsigned char>( static_cast<float>( *(itemBufferPtr + 1u) ) * textParameters.textColor.g );
226         *(bufferPtr + 2u) = static_cast<unsigned char>( static_cast<float>( *(itemBufferPtr + 2u) ) * textParameters.textColor.b );
227         *(bufferPtr + 3u) = static_cast<unsigned char>( static_cast<float>( *(itemBufferPtr + 3u) ) * textParameters.textColor.a );
228
229         itemBufferPtr += bytesPerPixel;
230         bufferPtr += bytesPerPixel;
231       }
232
233       itemPixelBuffer = buffer;
234     }
235
236     Dali::Toolkit::DevelText::UpdateBuffer(itemPixelBuffer, pixelBuffer, layoutX, layoutY, true);
237   }
238
239   PixelData pixelData = Devel::PixelBuffer::Convert( pixelBuffer );
240
241   Texture texture = Texture::New( TextureType::TEXTURE_2D,
242                                   pixelData.GetPixelFormat(),
243                                   pixelData.GetWidth(),
244                                   pixelData.GetHeight() );
245   texture.Upload(pixelData);
246
247   TextureSet textureSet = TextureSet::New();
248   textureSet.SetTexture( 0u, texture );
249
250   return textureSet;
251 }
252
253 } // namespace
254
255
256 /**
257  * @brief The main class of the demo.
258  */
259 class SimpleTextRendererExample : public ConnectionTracker
260 {
261 public:
262
263   SimpleTextRendererExample( Application& application )
264   : mApplication( application )
265   {
266     // Connect to the Application's Init signal
267     mApplication.InitSignal().Connect( this, &SimpleTextRendererExample::Create );
268   }
269
270   ~SimpleTextRendererExample()
271   {
272     // Nothing to do here.
273   }
274
275   /**
276    * One-time setup in response to Application InitSignal.
277    */
278   void Create( Application& application )
279   {
280     Stage stage = Stage::GetCurrent();
281     stage.SetBackgroundColor( Color::WHITE );
282     stage.SetBackgroundColor( Vector4( 0.04f, 0.345f, 0.392f, 1.0f ) );
283
284     stage.KeyEventSignal().Connect(this, &SimpleTextRendererExample::OnKeyEvent);
285
286     const std::string image1 = "<item 'width'=26 'height'=26 'url'='" + IMAGE1 + "'/>";
287     const std::string image2 = "<item 'width'=26 'height'=26/>";
288
289     Dali::Toolkit::DevelText::RendererParameters textParameters;
290     textParameters.text = "Hello " + image1 + " world " + image2 + " this " + image1 + " is " + image2 + " a " + image1 + " demo " + image2 + " of " + image1 + " circular " + image2 + " text " + image1 + " width " + image2 + " icons.";
291     textParameters.horizontalAlignment = "center";
292     textParameters.verticalAlignment = "center";
293     textParameters.circularAlignment = "center";
294     textParameters.fontFamily = "SamsungUI";
295     textParameters.fontWeight = "";
296     textParameters.fontWidth = "";
297     textParameters.fontSlant = "";
298     textParameters.layout = "circular";
299     textParameters.textColor = Color::BLACK;
300     textParameters.fontSize = 25.f;
301     textParameters.textWidth = 360u;
302     textParameters.textHeight = 360u;
303     textParameters.radius = 180u;
304     textParameters.beginAngle = 15.f;
305     textParameters.incrementAngle = 360.f;
306     textParameters.ellipsisEnabled = true;
307     textParameters.markupEnabled = true;
308
309     std::vector<std::string> embeddedItems = { IMAGE2, IMAGE2, IMAGE2, IMAGE2, IMAGE2 };
310
311     TextureSet textureSet = CreateTextureSet( textParameters, embeddedItems );
312
313     Renderer renderer = CreateRenderer();
314     renderer.SetTextures( textureSet );
315
316     Actor actor = Actor::New();
317     actor.SetAnchorPoint( AnchorPoint::CENTER );
318     actor.SetParentOrigin( ParentOrigin::CENTER );
319     actor.SetPosition( 0.f, 0.f);
320     actor.SetSize( 360.f, 360.f );
321     actor.SetColor( Color::WHITE );
322
323     actor.AddRenderer( renderer );
324
325     stage.Add( actor );
326   }
327
328   /**
329    * Main key event handler
330    */
331   void OnKeyEvent(const KeyEvent& event)
332   {
333     if(event.state == KeyEvent::Down)
334     {
335       if( IsKey( event, DALI_KEY_ESCAPE) || IsKey( event, DALI_KEY_BACK ) )
336       {
337         mApplication.Quit();
338       }
339     }
340   }
341
342 private:
343
344   Application& mApplication;
345 };
346
347 /** Entry point for Linux & Tizen applications */
348 int main( int argc, char **argv )
349 {
350   Application application = Application::New( &argc, &argv );
351
352   SimpleTextRendererExample test( application );
353
354   application.MainLoop();
355
356   return 0;
357 }