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