2 * Copyright (c) 2021 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.
18 #include "visual-factory-cache.h"
21 #include <dali/devel-api/adaptor-framework/image-loading.h>
22 #include <dali/devel-api/common/hash.h>
25 #include <dali-toolkit/internal/visuals/animated-vector-image/vector-animation-manager.h>
26 #include <dali-toolkit/internal/visuals/color/color-visual.h>
27 #include <dali-toolkit/internal/visuals/image-atlas-manager.h>
28 #include <dali-toolkit/internal/visuals/svg/svg-visual.h>
29 #include <dali-toolkit/internal/graphics/builtin-shader-extern-gen.h>
30 #include <dali/integration-api/debug.h>
42 * @brief Creates the geometry formed from the vertices and indices
44 * @param[in] vertices The vertices to generate the geometry from
45 * @param[in] indices The indices to generate the geometry from
46 * @return The geometry formed from the vertices and indices
48 Geometry GenerateGeometry(const Vector<Vector2>& vertices, const Vector<unsigned short>& indices)
50 Property::Map vertexFormat;
51 vertexFormat["aPosition"] = Property::VECTOR2;
52 VertexBuffer vertexBuffer = VertexBuffer::New(vertexFormat);
53 if(vertices.Size() > 0)
55 vertexBuffer.SetData(&vertices[0], vertices.Size());
58 // Create the geometry object
59 Geometry geometry = Geometry::New();
60 geometry.AddVertexBuffer(vertexBuffer);
61 if(indices.Size() > 0)
63 geometry.SetIndexBuffer(&indices[0], indices.Size());
70 * @brief Adds the indices to form a quad composed off two triangles where the indices are organised in a grid
72 * @param[out] indices The indices to add to
73 * @param[in] rowIdx The row index to start the quad
74 * @param[in] nextRowIdx The index to the next row
76 void AddQuadIndices(Vector<unsigned short>& indices, unsigned int rowIdx, unsigned int nextRowIdx)
78 indices.PushBack(rowIdx);
79 indices.PushBack(nextRowIdx + 1);
80 indices.PushBack(rowIdx + 1);
82 indices.PushBack(rowIdx);
83 indices.PushBack(nextRowIdx);
84 indices.PushBack(nextRowIdx + 1);
88 * @brief Adds the vertices to create for npatch
89 * @param[out] vertices The vertices to add to
90 * @param[in] x The x value of vector
91 * @param[in] y The y value of vector
93 void AddVertex(Vector<Vector2>& vertices, unsigned int x, unsigned int y)
95 vertices.PushBack(Vector2(x, y));
100 VisualFactoryCache::VisualFactoryCache(bool preMultiplyOnLoad)
101 : mSvgRasterizeThread(NULL),
102 mVectorAnimationManager(),
103 mPreMultiplyOnLoad(preMultiplyOnLoad),
104 mBrokenImageInfoContainer()
108 VisualFactoryCache::~VisualFactoryCache()
110 SvgRasterizeThread::TerminateThread(mSvgRasterizeThread);
113 Geometry VisualFactoryCache::GetGeometry(GeometryType type)
115 if(!mGeometry[type] && type == QUAD_GEOMETRY)
117 mGeometry[type] = CreateQuadGeometry();
120 return mGeometry[type];
123 void VisualFactoryCache::SaveGeometry(GeometryType type, Geometry geometry)
125 mGeometry[type] = geometry;
128 Shader VisualFactoryCache::GetShader(ShaderType type)
130 return mShader[type];
133 void VisualFactoryCache::SaveShader(ShaderType type, Shader shader)
135 mShader[type] = shader;
138 Geometry VisualFactoryCache::CreateQuadGeometry()
140 const float halfWidth = 0.5f;
141 const float halfHeight = 0.5f;
146 QuadVertex quadVertexData[4] =
148 {Vector2(-halfWidth, -halfHeight)},
149 {Vector2(-halfWidth, halfHeight)},
150 {Vector2(halfWidth, -halfHeight)},
151 {Vector2(halfWidth, halfHeight)}};
153 Property::Map quadVertexFormat;
154 quadVertexFormat["aPosition"] = Property::VECTOR2;
155 VertexBuffer quadVertices = VertexBuffer::New(quadVertexFormat);
156 quadVertices.SetData(quadVertexData, 4);
158 // Create the geometry object
159 Geometry geometry = Geometry::New();
160 geometry.AddVertexBuffer(quadVertices);
161 geometry.SetType(Geometry::TRIANGLE_STRIP);
166 ImageAtlasManagerPtr VisualFactoryCache::GetAtlasManager()
170 mAtlasManager = new ImageAtlasManager();
171 if(!mBrokenImageInfoContainer.empty())
173 mAtlasManager->SetBrokenImage(mBrokenImageInfoContainer[0].url);
177 return mAtlasManager;
180 TextureManager& VisualFactoryCache::GetTextureManager()
182 return mTextureManager;
185 NPatchLoader& VisualFactoryCache::GetNPatchLoader()
187 return mNPatchLoader;
190 SvgRasterizeThread* VisualFactoryCache::GetSVGRasterizationThread()
192 if(!mSvgRasterizeThread)
194 mSvgRasterizeThread = new SvgRasterizeThread();
195 mSvgRasterizeThread->Start();
197 return mSvgRasterizeThread;
200 VectorAnimationManager& VisualFactoryCache::GetVectorAnimationManager()
202 if(!mVectorAnimationManager)
204 mVectorAnimationManager = std::unique_ptr<VectorAnimationManager>(new VectorAnimationManager());
206 return *mVectorAnimationManager;
209 Geometry VisualFactoryCache::CreateGridGeometry(Uint16Pair gridSize)
211 uint16_t gridWidth = gridSize.GetWidth();
212 uint16_t gridHeight = gridSize.GetHeight();
215 Vector<Vector2> vertices;
216 vertices.Reserve((gridWidth + 1) * (gridHeight + 1));
218 for(int y = 0; y < gridHeight + 1; ++y)
220 for(int x = 0; x < gridWidth + 1; ++x)
222 vertices.PushBack(Vector2((float)x / gridWidth - 0.5f, (float)y / gridHeight - 0.5f));
227 Vector<unsigned short> indices;
228 indices.Reserve((gridWidth + 2) * gridHeight * 2 - 2);
230 for(unsigned int row = 0u; row < gridHeight; ++row)
232 unsigned int rowStartIndex = row * (gridWidth + 1u);
233 unsigned int nextRowStartIndex = rowStartIndex + gridWidth + 1u;
235 if(row != 0u) // degenerate index on non-first row
237 indices.PushBack(rowStartIndex);
240 for(unsigned int column = 0u; column < gridWidth + 1u; column++) // main strip
242 indices.PushBack(rowStartIndex + column);
243 indices.PushBack(nextRowStartIndex + column);
246 if(row != gridHeight - 1u) // degenerate index on non-last row
248 indices.PushBack(nextRowStartIndex + gridWidth);
252 Property::Map vertexFormat;
253 vertexFormat["aPosition"] = Property::VECTOR2;
254 VertexBuffer vertexBuffer = VertexBuffer::New(vertexFormat);
255 if(vertices.Size() > 0)
257 vertexBuffer.SetData(&vertices[0], vertices.Size());
260 Property::Map indexFormat;
261 indexFormat["indices"] = Property::INTEGER;
262 VertexBuffer indexVertexBuffer = VertexBuffer::New(indexFormat);
264 // Create the geometry object
265 Geometry geometry = Geometry::New();
266 geometry.AddVertexBuffer(vertexBuffer);
267 if(indices.Size() > 0)
269 geometry.SetIndexBuffer(&indices[0], indices.Size());
272 geometry.SetType(Geometry::TRIANGLE_STRIP);
277 Texture VisualFactoryCache::GetBrokenVisualImage(uint32_t brokenIndex)
279 if(!(mBrokenImageInfoContainer[brokenIndex].texture))
282 Devel::PixelBuffer pixelBuffer = LoadImageFromFile(mBrokenImageInfoContainer[brokenIndex].url);
285 pixelData = Devel::PixelBuffer::Convert(pixelBuffer); // takes ownership of buffer
286 mBrokenImageInfoContainer[brokenIndex].texture = Texture::New(Dali::TextureType::TEXTURE_2D, pixelData.GetPixelFormat(), pixelData.GetWidth(), pixelData.GetHeight());
287 mBrokenImageInfoContainer[brokenIndex].texture.Upload(pixelData);
288 mBrokenImageInfoContainer[brokenIndex].width = pixelData.GetWidth();
289 mBrokenImageInfoContainer[brokenIndex].height = pixelData.GetHeight();
292 return mBrokenImageInfoContainer[brokenIndex].texture;
295 void VisualFactoryCache::SetPreMultiplyOnLoad(bool preMultiply)
297 mPreMultiplyOnLoad = preMultiply;
300 bool VisualFactoryCache::GetPreMultiplyOnLoad()
302 return mPreMultiplyOnLoad;
305 void VisualFactoryCache::SetBrokenImageUrl(const std::vector<std::string>& brokenImageUrlList)
307 mBrokenImageInfoContainer.clear();
308 mBrokenImageInfoContainer.assign(brokenImageUrlList.size(), BrokenImageInfo());
309 for(unsigned int i = 0; i < brokenImageUrlList.size(); i++)
311 mBrokenImageInfoContainer[i].url = brokenImageUrlList[i];
315 VisualUrl::Type VisualFactoryCache::GetBrokenImageVisualType(int index)
317 return mBrokenImageInfoContainer[index].visualType;
320 Geometry VisualFactoryCache::CreateNPatchGeometry(Uint16Pair gridSize)
322 uint16_t gridWidth = gridSize.GetWidth();
323 uint16_t gridHeight = gridSize.GetHeight();
326 Vector<Vector2> vertices;
327 vertices.Reserve((gridWidth + 1) * (gridHeight + 1));
329 for(int y = 0; y < gridHeight + 1; ++y)
331 for(int x = 0; x < gridWidth + 1; ++x)
333 AddVertex(vertices, x, y);
338 Vector<unsigned short> indices;
339 indices.Reserve(gridWidth * gridHeight * 6);
341 unsigned int rowIdx = 0;
342 unsigned int nextRowIdx = gridWidth + 1;
343 for(int y = 0; y < gridHeight; ++y, ++nextRowIdx, ++rowIdx)
345 for(int x = 0; x < gridWidth; ++x, ++nextRowIdx, ++rowIdx)
347 AddQuadIndices(indices, rowIdx, nextRowIdx);
351 return GenerateGeometry(vertices, indices);
354 Geometry VisualFactoryCache::GetNPatchGeometry(int index)
357 const NPatchData* data;
358 if(mNPatchLoader.GetNPatchData(mBrokenImageInfoContainer[index].npatchId, data) && data->GetLoadingState() == NPatchData::LoadingState::LOAD_COMPLETE)
360 if(data->GetStretchPixelsX().Size() == 1 && data->GetStretchPixelsY().Size() == 1)
362 geometry = GetGeometry(VisualFactoryCache::NINE_PATCH_GEOMETRY);
365 geometry = CreateNPatchGeometry(Uint16Pair(3,3));
366 SaveGeometry(VisualFactoryCache::NINE_PATCH_GEOMETRY, geometry);
369 else if(data->GetStretchPixelsX().Size() > 0 || data->GetStretchPixelsY().Size() > 0)
371 Uint16Pair gridSize(2 * data->GetStretchPixelsX().Size() + 1, 2 * data->GetStretchPixelsY().Size() + 1);
372 geometry = CreateNPatchGeometry(gridSize);
377 // no N patch data so use default geometry
378 geometry = GetGeometry(VisualFactoryCache::NINE_PATCH_GEOMETRY);
381 geometry = CreateNPatchGeometry(Uint16Pair(3,3));
382 SaveGeometry(VisualFactoryCache::NINE_PATCH_GEOMETRY, geometry);
388 Shader VisualFactoryCache::GetNPatchShader(int index)
391 const NPatchData* data;
392 // 0 is either no data (load failed?) or no stretch regions on image
393 // for both cases we use the default shader
394 NPatchUtility::StretchRanges::SizeType xStretchCount = 0;
395 NPatchUtility::StretchRanges::SizeType yStretchCount = 0;
397 // ask loader for the regions
398 if(mNPatchLoader.GetNPatchData(mBrokenImageInfoContainer[index].npatchId, data))
400 xStretchCount = data->GetStretchPixelsX().Count();
401 yStretchCount = data->GetStretchPixelsY().Count();
404 if(DALI_LIKELY((xStretchCount == 0 && yStretchCount == 0)))
406 shader = GetShader(VisualFactoryCache::NINE_PATCH_SHADER);
407 if(DALI_UNLIKELY(!shader))
409 shader = Shader::New(SHADER_NPATCH_VISUAL_3X3_SHADER_VERT, SHADER_NPATCH_VISUAL_SHADER_FRAG);
411 // Only cache vanilla 9 patch shaders
412 SaveShader(VisualFactoryCache::NINE_PATCH_SHADER, shader);
415 else if(xStretchCount > 0 || yStretchCount > 0)
417 std::stringstream vertexShader;
418 vertexShader << "#define FACTOR_SIZE_X " << xStretchCount + 2 << "\n"
419 << "#define FACTOR_SIZE_Y " << yStretchCount + 2 << "\n"
420 << SHADER_NPATCH_VISUAL_SHADER_VERT;
421 shader = Shader::New(vertexShader.str(), SHADER_NPATCH_VISUAL_SHADER_FRAG);
426 void VisualFactoryCache::RegisterStretchProperties(Renderer& renderer, const char* uniformName, const NPatchUtility::StretchRanges& stretchPixels, uint16_t imageExtent)
428 uint16_t prevEnd = 0;
429 uint16_t prevFix = 0;
430 uint16_t prevStretch = 0;
432 for(NPatchUtility::StretchRanges::ConstIterator it = stretchPixels.Begin(); it != stretchPixels.End(); ++it, ++i)
434 uint16_t start = it->GetX();
435 uint16_t end = it->GetY();
437 uint16_t fix = prevFix + start - prevEnd;
438 uint16_t stretch = prevStretch + end - start;
440 std::stringstream uniform;
441 uniform << uniformName << "[" << i << "]";
442 renderer.RegisterProperty(uniform.str(), Vector2(fix, stretch));
446 prevStretch = stretch;
450 prevFix += imageExtent - prevEnd;
451 std::stringstream uniform;
452 uniform << uniformName << "[" << i << "]";
453 renderer.RegisterProperty(uniform.str(), Vector2(prevFix, prevStretch));
457 void VisualFactoryCache::ApplyTextureAndUniforms(Renderer& renderer, int index)
459 const NPatchData* data;
460 TextureSet textureSet;
461 if(mNPatchLoader.GetNPatchData(mBrokenImageInfoContainer[index].npatchId, data) && data->GetLoadingState() == NPatchData::LoadingState::LOAD_COMPLETE)
463 textureSet = data->GetTextures();
464 mBrokenImageInfoContainer[index].texture = data->GetTextures().GetTexture(0);
466 if(data->GetStretchPixelsX().Size() == 1 && data->GetStretchPixelsY().Size() == 1)
468 //special case for 9 patch
469 Uint16Pair stretchX = data->GetStretchPixelsX()[0];
470 Uint16Pair stretchY = data->GetStretchPixelsY()[0];
472 uint16_t stretchWidth = (stretchX.GetY() >= stretchX.GetX()) ? stretchX.GetY() - stretchX.GetX() : 0;
473 uint16_t stretchHeight = (stretchY.GetY() >= stretchY.GetX()) ? stretchY.GetY() - stretchY.GetX() : 0;
475 renderer.RegisterProperty("uFixed[0]", Vector2::ZERO);
476 renderer.RegisterProperty("uFixed[1]", Vector2(stretchX.GetX(), stretchY.GetX()));
477 renderer.RegisterProperty("uFixed[2]", Vector2(data->GetCroppedWidth() - stretchWidth, data->GetCroppedHeight() - stretchHeight));
478 renderer.RegisterProperty("uStretchTotal", Vector2(stretchWidth, stretchHeight));
482 renderer.RegisterProperty("uNinePatchFactorsX[0]", Vector2::ZERO);
483 renderer.RegisterProperty("uNinePatchFactorsY[0]", Vector2::ZERO);
485 RegisterStretchProperties(renderer, "uNinePatchFactorsX", data->GetStretchPixelsX(), data->GetCroppedWidth());
486 RegisterStretchProperties(renderer, "uNinePatchFactorsY", data->GetStretchPixelsY(), data->GetCroppedHeight());
488 renderer.SetTextures(textureSet);
492 void VisualFactoryCache::UpdateBrokenImageRenderer(Renderer& renderer, const Vector2& size)
494 // Load Information for broken image
495 for(uint32_t index = 0; index < mBrokenImageInfoContainer.size(); index++)
497 if(mBrokenImageInfoContainer[index].width == 0 && mBrokenImageInfoContainer[index].height == 0)
499 if(!mBrokenImageInfoContainer[index].url.empty())
501 VisualUrl visualUrl(mBrokenImageInfoContainer[index].url);
502 mBrokenImageInfoContainer[index].visualType = visualUrl.GetType();
503 if(mBrokenImageInfoContainer[index].visualType == VisualUrl::Type::N_PATCH)
505 const NPatchData* data;
507 mBrokenImageInfoContainer[index].npatchId = mNPatchLoader.Load( mTextureManager, NULL, mBrokenImageInfoContainer[index].url, border, mPreMultiplyOnLoad, true);
508 if(mNPatchLoader.GetNPatchData(mBrokenImageInfoContainer[index].npatchId, data) && data->GetLoadingState() == NPatchData::LoadingState::LOAD_COMPLETE)
510 mBrokenImageInfoContainer[index].width = data->GetCroppedWidth();
511 mBrokenImageInfoContainer[index].height = data->GetCroppedHeight();
515 DALI_LOG_ERROR("Can't update renderer for broken image. maybe image loading is failed [path:%s] \n",mBrokenImageInfoContainer[index].url.c_str());
520 GetBrokenVisualImage(index);
526 // Set Texutre to renderer
527 int brokenIndex = GetProperBrokenImageIndex(size);
528 if(GetBrokenImageVisualType(brokenIndex) == VisualUrl::N_PATCH)
530 // Set geometry and shader for npatch
531 Geometry geometry = GetNPatchGeometry(brokenIndex);
532 Shader shader = GetNPatchShader(brokenIndex);
533 renderer.SetGeometry(geometry);
534 renderer.SetShader(shader);
535 ApplyTextureAndUniforms(renderer, brokenIndex);
539 Texture brokenImage = GetBrokenVisualImage(brokenIndex);
540 TextureSet textureSet = TextureSet::New();
541 textureSet.SetTexture(0u, brokenImage);
542 renderer.SetTextures(textureSet);
546 int32_t VisualFactoryCache::GetProperBrokenImageIndex(const Vector2& size)
548 // Sets the default broken type
549 int32_t returnIndex = 0;
550 if((size.width == 0 || size.height == 0))
552 // To do : Need to add observer about size
556 // Find the proper value if we know the size of the image
557 for(int32_t index = static_cast<int32_t>(mBrokenImageInfoContainer.size()) - 1; index >= 0; index--)
559 // Skip if the value is not set
560 if(mBrokenImageInfoContainer[index].width == 0 || mBrokenImageInfoContainer[index].height == 0)
565 if(mBrokenImageInfoContainer[index].width < size.width && mBrokenImageInfoContainer[index].height < size.height)
575 } // namespace Internal
577 } // namespace Toolkit