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.
19 #include "npatch-visual.h"
22 #include <dali/devel-api/adaptor-framework/image-loading.h>
23 #include <dali/devel-api/rendering/renderer-devel.h>
24 #include <dali/integration-api/debug.h>
25 #include <dali/devel-api/common/stage.h>
28 #include <dali-toolkit/devel-api/visuals/image-visual-properties-devel.h>
29 #include <dali-toolkit/internal/graphics/builtin-shader-extern-gen.h>
30 #include <dali-toolkit/internal/visuals/image-visual-shader-factory.h>
31 #include <dali-toolkit/internal/visuals/npatch-loader.h>
32 #include <dali-toolkit/internal/visuals/rendering-addon.h>
33 #include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
34 #include <dali-toolkit/internal/visuals/visual-base-impl.h>
35 #include <dali-toolkit/internal/visuals/visual-factory-cache.h>
36 #include <dali-toolkit/internal/visuals/visual-factory-impl.h>
37 #include <dali-toolkit/internal/visuals/visual-string-constants.h>
38 #include <dali-toolkit/public-api/visuals/visual-properties.h>
49 * @brief Creates the geometry formed from the vertices and indices
51 * @param[in] vertices The vertices to generate the geometry from
52 * @param[in] indices The indices to generate the geometry from
53 * @return The geometry formed from the vertices and indices
55 Geometry GenerateGeometry(const Vector<Vector2>& vertices, const Vector<unsigned short>& indices)
57 Property::Map vertexFormat;
58 vertexFormat["aPosition"] = Property::VECTOR2;
59 VertexBuffer vertexBuffer = VertexBuffer::New(vertexFormat);
60 if(vertices.Size() > 0)
62 vertexBuffer.SetData(&vertices[0], vertices.Size());
65 // Create the geometry object
66 Geometry geometry = Geometry::New();
67 geometry.AddVertexBuffer(vertexBuffer);
68 if(indices.Size() > 0)
70 geometry.SetIndexBuffer(&indices[0], indices.Size());
77 * @brief Adds the indices to form a quad composed off two triangles where the indices are organised in a grid
79 * @param[out] indices The indices to add to
80 * @param[in] rowIdx The row index to start the quad
81 * @param[in] nextRowIdx The index to the next row
83 void AddQuadIndices(Vector<unsigned short>& indices, unsigned int rowIdx, unsigned int nextRowIdx)
85 indices.PushBack(rowIdx);
86 indices.PushBack(nextRowIdx + 1);
87 indices.PushBack(rowIdx + 1);
89 indices.PushBack(rowIdx);
90 indices.PushBack(nextRowIdx);
91 indices.PushBack(nextRowIdx + 1);
94 void AddVertex(Vector<Vector2>& vertices, unsigned int x, unsigned int y)
96 vertices.PushBack(Vector2(x, y));
99 void RegisterStretchProperties(Renderer& renderer, const char* uniformName, const NPatchUtility::StretchRanges& stretchPixels, uint16_t imageExtent)
101 uint16_t prevEnd = 0;
102 uint16_t prevFix = 0;
103 uint16_t prevStretch = 0;
105 for(NPatchUtility::StretchRanges::ConstIterator it = stretchPixels.Begin(); it != stretchPixels.End(); ++it, ++i)
107 uint16_t start = it->GetX();
108 uint16_t end = it->GetY();
110 uint16_t fix = prevFix + start - prevEnd;
111 uint16_t stretch = prevStretch + end - start;
113 std::stringstream uniform;
114 uniform << uniformName << "[" << i << "]";
115 renderer.RegisterProperty(uniform.str(), Vector2(fix, stretch));
119 prevStretch = stretch;
123 prevFix += imageExtent - prevEnd;
124 std::stringstream uniform;
125 uniform << uniformName << "[" << i << "]";
126 renderer.RegisterProperty(uniform.str(), Vector2(prevFix, prevStretch));
130 } //unnamed namespace
132 /////////////////NPatchVisual////////////////
134 NPatchVisualPtr NPatchVisual::New(VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, const VisualUrl& imageUrl, const Property::Map& properties)
136 NPatchVisualPtr nPatchVisual(new NPatchVisual(factoryCache, shaderFactory));
137 nPatchVisual->mImageUrl = imageUrl;
138 nPatchVisual->SetProperties(properties);
139 nPatchVisual->Initialize();
143 NPatchVisualPtr NPatchVisual::New(VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, const VisualUrl& imageUrl)
145 NPatchVisualPtr nPatchVisual(new NPatchVisual(factoryCache, shaderFactory));
146 nPatchVisual->mImageUrl = imageUrl;
147 nPatchVisual->Initialize();
151 void NPatchVisual::LoadImages()
153 TextureManager& textureManager = mFactoryCache.GetTextureManager();
154 bool synchronousLoading = mImpl->mFlags & Impl::IS_SYNCHRONOUS_RESOURCE_LOADING;
156 if(mId == NPatchData::INVALID_NPATCH_DATA_ID && (mImageUrl.IsLocalResource() || mImageUrl.IsBufferResource()))
158 bool preMultiplyOnLoad = IsPreMultipliedAlphaEnabled() && !mImpl->mCustomShader ? true : false;
159 mId = mLoader.Load(textureManager, this, mImageUrl, mBorder, preMultiplyOnLoad, synchronousLoading);
161 const NPatchData* data;
162 if(mLoader.GetNPatchData(mId, data) && data->GetLoadingState() == NPatchData::LoadingState::LOAD_COMPLETE)
164 EnablePreMultipliedAlpha(data->IsPreMultiplied());
168 if(!mAuxiliaryPixelBuffer && mAuxiliaryUrl.IsValid() && (mAuxiliaryUrl.IsLocalResource() || mAuxiliaryUrl.IsBufferResource()))
170 // Load the auxiliary image
171 auto preMultiplyOnLoading = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
172 mAuxiliaryPixelBuffer = textureManager.LoadPixelBuffer(mAuxiliaryUrl, Dali::ImageDimensions(), FittingMode::DEFAULT, SamplingMode::BOX_THEN_LINEAR, synchronousLoading, this, true, preMultiplyOnLoading);
176 void NPatchVisual::GetNaturalSize(Vector2& naturalSize)
181 // load now if not already loaded
182 const NPatchData* data;
183 if(mLoader.GetNPatchData(mId, data) && data->GetLoadingState() != NPatchData::LoadingState::LOADING)
185 naturalSize.x = data->GetCroppedWidth();
186 naturalSize.y = data->GetCroppedHeight();
190 if(mImageUrl.IsValid())
192 ImageDimensions dimensions = Dali::GetOriginalImageSize(mImageUrl.GetUrl());
193 if(dimensions != ImageDimensions(0, 0))
195 naturalSize.x = dimensions.GetWidth();
196 naturalSize.y = dimensions.GetHeight();
201 if(mAuxiliaryPixelBuffer)
203 naturalSize.x = std::max(naturalSize.x, float(mAuxiliaryPixelBuffer.GetWidth()));
204 naturalSize.y = std::max(naturalSize.y, float(mAuxiliaryPixelBuffer.GetHeight()));
208 void NPatchVisual::DoSetProperties(const Property::Map& propertyMap)
210 // URL is already passed in via constructor
212 Property::Value* borderOnlyValue = propertyMap.Find(Toolkit::ImageVisual::Property::BORDER_ONLY, BORDER_ONLY);
215 borderOnlyValue->Get(mBorderOnly);
218 Property::Value* borderValue = propertyMap.Find(Toolkit::ImageVisual::Property::BORDER, BORDER);
219 if(borderValue && !borderValue->Get(mBorder)) // If value exists and is rect, just set mBorder
221 // Not a rect so try vector4
223 if(borderValue->Get(border))
225 mBorder.left = static_cast<int>(border.x);
226 mBorder.right = static_cast<int>(border.y);
227 mBorder.bottom = static_cast<int>(border.z);
228 mBorder.top = static_cast<int>(border.w);
232 Property::Value* auxImage = propertyMap.Find(Toolkit::DevelImageVisual::Property::AUXILIARY_IMAGE, AUXILIARY_IMAGE_NAME);
236 if(auxImage->Get(url))
242 Property::Value* auxImageAlpha = propertyMap.Find(Toolkit::DevelImageVisual::Property::AUXILIARY_IMAGE_ALPHA, AUXILIARY_IMAGE_ALPHA_NAME);
245 auxImageAlpha->Get(mAuxiliaryImageAlpha);
248 Property::Value* synchronousLoading = propertyMap.Find(Toolkit::ImageVisual::Property::SYNCHRONOUS_LOADING, SYNCHRONOUS_LOADING);
249 if(synchronousLoading)
252 synchronousLoading->Get(sync);
255 mImpl->mFlags |= Impl::IS_SYNCHRONOUS_RESOURCE_LOADING;
259 mImpl->mFlags &= ~Impl::IS_SYNCHRONOUS_RESOURCE_LOADING;
263 Property::Value* releasePolicy = propertyMap.Find(Toolkit::ImageVisual::Property::RELEASE_POLICY, RELEASE_POLICY_NAME);
266 releasePolicy->Get(mReleasePolicy);
270 void NPatchVisual::DoSetOnScene(Actor& actor)
272 // load when first go on stage
275 const NPatchData* data;
276 if(mLoader.GetNPatchData(mId, data))
278 Geometry geometry = CreateGeometry();
279 Shader shader = CreateShader();
281 mImpl->mRenderer.SetGeometry(geometry);
282 mImpl->mRenderer.SetShader(shader);
284 mPlacementActor = actor;
285 if(data->GetLoadingState() != NPatchData::LoadingState::LOADING)
287 if(RenderingAddOn::Get().IsValid())
289 RenderingAddOn::Get().SubmitRenderTask(mImpl->mRenderer, data->GetRenderingMap());
292 ApplyTextureAndUniforms();
293 actor.AddRenderer(mImpl->mRenderer);
294 mPlacementActor.Reset();
296 // npatch loaded and ready to display
297 ResourceReady(Toolkit::Visual::ResourceStatus::READY);
302 void NPatchVisual::DoSetOffScene(Actor& actor)
304 if((mId != NPatchData::INVALID_NPATCH_DATA_ID) && mReleasePolicy == Toolkit::ImageVisual::ReleasePolicy::DETACHED)
306 mLoader.Remove(mId, this);
307 mImpl->mResourceStatus = Toolkit::Visual::ResourceStatus::PREPARING;
308 mId = NPatchData::INVALID_NPATCH_DATA_ID;
311 actor.RemoveRenderer(mImpl->mRenderer);
312 mPlacementActor.Reset();
315 void NPatchVisual::OnSetTransform()
319 mImpl->mTransform.RegisterUniforms(mImpl->mRenderer, Direction::LEFT_TO_RIGHT);
323 void NPatchVisual::DoCreatePropertyMap(Property::Map& map) const
326 bool sync = IsSynchronousLoadingRequired();
327 map.Insert(Toolkit::ImageVisual::Property::SYNCHRONOUS_LOADING, sync);
328 map.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::N_PATCH);
329 map.Insert(Toolkit::ImageVisual::Property::URL, mImageUrl.GetUrl());
330 map.Insert(Toolkit::ImageVisual::Property::BORDER_ONLY, mBorderOnly);
331 map.Insert(Toolkit::ImageVisual::Property::BORDER, mBorder);
332 map.Insert(Toolkit::ImageVisual::Property::RELEASE_POLICY, mReleasePolicy);
334 if(mAuxiliaryUrl.IsValid())
336 map.Insert(Toolkit::DevelImageVisual::Property::AUXILIARY_IMAGE, mAuxiliaryUrl.GetUrl());
337 map.Insert(Toolkit::DevelImageVisual::Property::AUXILIARY_IMAGE_ALPHA, mAuxiliaryImageAlpha);
341 void NPatchVisual::DoCreateInstancePropertyMap(Property::Map& map) const
343 if(mAuxiliaryUrl.IsValid())
345 map.Insert(Toolkit::DevelImageVisual::Property::AUXILIARY_IMAGE, mAuxiliaryUrl.GetUrl());
346 map.Insert(Toolkit::DevelImageVisual::Property::AUXILIARY_IMAGE_ALPHA, mAuxiliaryImageAlpha);
350 NPatchVisual::NPatchVisual(VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory)
351 : Visual::Base(factoryCache, Visual::FittingMode::FILL, Toolkit::Visual::N_PATCH),
353 mLoader(factoryCache.GetNPatchLoader()),
354 mImageVisualShaderFactory(shaderFactory),
357 mId(NPatchData::INVALID_NPATCH_DATA_ID),
360 mAuxiliaryImageAlpha(0.0f),
361 mReleasePolicy(Toolkit::ImageVisual::ReleasePolicy::DETACHED)
363 EnablePreMultipliedAlpha(mFactoryCache.GetPreMultiplyOnLoad());
366 NPatchVisual::~NPatchVisual()
368 if(Stage::IsInstalled() && (mId != NPatchData::INVALID_NPATCH_DATA_ID) && (mReleasePolicy != Toolkit::ImageVisual::ReleasePolicy::NEVER))
370 mLoader.Remove(mId, this);
371 mId = NPatchData::INVALID_NPATCH_DATA_ID;
375 void NPatchVisual::OnInitialize()
377 // Get basic geometry and shader
378 Geometry geometry = mFactoryCache.GetGeometry(VisualFactoryCache::QUAD_GEOMETRY);
379 Shader shader = mImageVisualShaderFactory.GetShader(
381 TextureAtlas::DISABLED,
382 DefaultTextureWrapMode::APPLY,
383 RoundedCorner::DISABLED,
387 mImpl->mRenderer = Renderer::New(geometry, shader);
389 //Register transform properties
390 mImpl->mTransform.RegisterUniforms(mImpl->mRenderer, Direction::LEFT_TO_RIGHT);
393 Geometry NPatchVisual::CreateGeometry()
396 const NPatchData* data;
397 if(mLoader.GetNPatchData(mId, data) && data->GetLoadingState() == NPatchData::LoadingState::LOAD_COMPLETE)
399 if(data->GetStretchPixelsX().Size() == 1 && data->GetStretchPixelsY().Size() == 1)
401 if(DALI_UNLIKELY(mBorderOnly))
403 geometry = GetNinePatchGeometry(VisualFactoryCache::NINE_PATCH_BORDER_GEOMETRY);
407 if(data->GetRenderingMap())
409 uint32_t elementCount[2];
410 geometry = RenderingAddOn::Get().CreateGeometryGrid(data->GetRenderingMap(), Uint16Pair(3, 3), elementCount);
413 RenderingAddOn::Get().SubmitRenderTask(mImpl->mRenderer, data->GetRenderingMap());
418 geometry = GetNinePatchGeometry(VisualFactoryCache::NINE_PATCH_GEOMETRY);
422 else if(data->GetStretchPixelsX().Size() > 0 || data->GetStretchPixelsY().Size() > 0)
424 Uint16Pair gridSize(2 * data->GetStretchPixelsX().Size() + 1, 2 * data->GetStretchPixelsY().Size() + 1);
425 if(!data->GetRenderingMap())
427 geometry = !mBorderOnly ? CreateGridGeometry(gridSize) : CreateBorderGeometry(gridSize);
431 uint32_t elementCount[2];
432 geometry = !mBorderOnly ? RenderingAddOn::Get().CreateGeometryGrid(data->GetRenderingMap(), gridSize, elementCount) : CreateBorderGeometry(gridSize);
435 RenderingAddOn::Get().SubmitRenderTask(mImpl->mRenderer, data->GetRenderingMap());
442 // no N patch data so use default geometry
443 geometry = GetNinePatchGeometry(VisualFactoryCache::NINE_PATCH_GEOMETRY);
448 Shader NPatchVisual::CreateShader()
451 const NPatchData* data;
452 // 0 is either no data (load failed?) or no stretch regions on image
453 // for both cases we use the default shader
454 NPatchUtility::StretchRanges::SizeType xStretchCount = 0;
455 NPatchUtility::StretchRanges::SizeType yStretchCount = 0;
457 auto fragmentShader = mAuxiliaryPixelBuffer ? SHADER_NPATCH_VISUAL_MASK_SHADER_FRAG
458 : SHADER_NPATCH_VISUAL_SHADER_FRAG;
459 auto shaderType = mAuxiliaryPixelBuffer ? VisualFactoryCache::NINE_PATCH_MASK_SHADER
460 : VisualFactoryCache::NINE_PATCH_SHADER;
462 // ask loader for the regions
463 if(mLoader.GetNPatchData(mId, data))
465 xStretchCount = data->GetStretchPixelsX().Count();
466 yStretchCount = data->GetStretchPixelsY().Count();
469 if(DALI_LIKELY(!mImpl->mCustomShader))
471 if(DALI_LIKELY((xStretchCount == 1 && yStretchCount == 1) ||
472 (xStretchCount == 0 && yStretchCount == 0)))
474 shader = mFactoryCache.GetShader(shaderType);
475 if(DALI_UNLIKELY(!shader))
477 shader = Shader::New(SHADER_NPATCH_VISUAL_3X3_SHADER_VERT, fragmentShader);
478 // Only cache vanilla 9 patch shaders
479 mFactoryCache.SaveShader(shaderType, shader);
482 else if(xStretchCount > 0 || yStretchCount > 0)
484 std::stringstream vertexShader;
485 vertexShader << "#define FACTOR_SIZE_X " << xStretchCount + 2 << "\n"
486 << "#define FACTOR_SIZE_Y " << yStretchCount + 2 << "\n"
487 << SHADER_NPATCH_VISUAL_SHADER_VERT;
489 shader = Shader::New(vertexShader.str(), fragmentShader);
494 Dali::Shader::Hint::Value hints = Dali::Shader::Hint::NONE;
496 if(!mImpl->mCustomShader->mFragmentShader.empty())
498 fragmentShader = mImpl->mCustomShader->mFragmentShader.c_str();
500 hints = mImpl->mCustomShader->mHints;
502 /* Apply Custom Vertex Shader only if image is 9-patch */
503 if((xStretchCount == 1 && yStretchCount == 1) ||
504 (xStretchCount == 0 && yStretchCount == 0))
506 const char* vertexShader = SHADER_NPATCH_VISUAL_3X3_SHADER_VERT.data();
508 if(!mImpl->mCustomShader->mVertexShader.empty())
510 vertexShader = mImpl->mCustomShader->mVertexShader.c_str();
512 shader = Shader::New(vertexShader, fragmentShader, hints);
514 else if(xStretchCount > 0 || yStretchCount > 0)
516 std::stringstream vertexShader;
517 vertexShader << "#define FACTOR_SIZE_X " << xStretchCount + 2 << "\n"
518 << "#define FACTOR_SIZE_Y " << yStretchCount + 2 << "\n"
519 << SHADER_NPATCH_VISUAL_SHADER_VERT;
521 shader = Shader::New(vertexShader.str(), fragmentShader, hints);
528 void NPatchVisual::ApplyTextureAndUniforms()
530 const NPatchData* data;
531 TextureSet textureSet;
533 if(mLoader.GetNPatchData(mId, data) && data->GetLoadingState() == NPatchData::LoadingState::LOAD_COMPLETE)
535 textureSet = data->GetTextures();
537 if(data->GetStretchPixelsX().Size() == 1 && data->GetStretchPixelsY().Size() == 1)
539 //special case for 9 patch
540 Uint16Pair stretchX = data->GetStretchPixelsX()[0];
541 Uint16Pair stretchY = data->GetStretchPixelsY()[0];
543 uint16_t stretchWidth = (stretchX.GetY() >= stretchX.GetX()) ? stretchX.GetY() - stretchX.GetX() : 0;
544 uint16_t stretchHeight = (stretchY.GetY() >= stretchY.GetX()) ? stretchY.GetY() - stretchY.GetX() : 0;
546 mImpl->mRenderer.RegisterProperty("uFixed[0]", Vector2::ZERO);
547 mImpl->mRenderer.RegisterProperty("uFixed[1]", Vector2(stretchX.GetX(), stretchY.GetX()));
548 mImpl->mRenderer.RegisterProperty("uFixed[2]", Vector2(data->GetCroppedWidth() - stretchWidth, data->GetCroppedHeight() - stretchHeight));
549 mImpl->mRenderer.RegisterProperty("uStretchTotal", Vector2(stretchWidth, stretchHeight));
553 mImpl->mRenderer.RegisterProperty("uNinePatchFactorsX[0]", Vector2::ZERO);
554 mImpl->mRenderer.RegisterProperty("uNinePatchFactorsY[0]", Vector2::ZERO);
556 RegisterStretchProperties(mImpl->mRenderer, "uNinePatchFactorsX", data->GetStretchPixelsX(), data->GetCroppedWidth());
557 RegisterStretchProperties(mImpl->mRenderer, "uNinePatchFactorsY", data->GetStretchPixelsY(), data->GetCroppedHeight());
562 DALI_LOG_ERROR("The N patch image '%s' is not a valid N patch image\n", mImageUrl.GetUrl().c_str());
563 textureSet = TextureSet::New();
565 Actor actor = mPlacementActor.GetHandle();
566 Vector2 imageSize = Vector2::ZERO;
569 imageSize = actor.GetProperty(Actor::Property::SIZE).Get<Vector2>();
571 mFactoryCache.UpdateBrokenImageRenderer(mImpl->mRenderer, imageSize);
572 Texture croppedImage = mImpl->mRenderer.GetTextures().GetTexture(0);
573 textureSet.SetTexture(0u, croppedImage);
574 mImpl->mRenderer.RegisterProperty("uFixed[0]", Vector2::ZERO);
575 mImpl->mRenderer.RegisterProperty("uFixed[1]", Vector2::ZERO);
576 mImpl->mRenderer.RegisterProperty("uFixed[2]", Vector2::ZERO);
577 mImpl->mRenderer.RegisterProperty("uStretchTotal", Vector2(croppedImage.GetWidth(), croppedImage.GetHeight()));
580 if(mAuxiliaryPixelBuffer)
582 // If the auxiliary image is smaller than the un-stretched NPatch, use CPU resizing to enlarge it to the
583 // same size as the unstretched NPatch. This will give slightly higher quality results than just relying
584 // on GL interpolation alone.
585 if(mAuxiliaryPixelBuffer.GetWidth() < data->GetCroppedWidth() &&
586 mAuxiliaryPixelBuffer.GetHeight() < data->GetCroppedHeight())
588 mAuxiliaryPixelBuffer.Resize(data->GetCroppedWidth(), data->GetCroppedHeight());
591 // Note, this resets mAuxiliaryPixelBuffer handle
592 auto auxiliaryPixelData = Devel::PixelBuffer::Convert(mAuxiliaryPixelBuffer);
594 auto texture = Texture::New(TextureType::TEXTURE_2D,
595 auxiliaryPixelData.GetPixelFormat(),
596 auxiliaryPixelData.GetWidth(),
597 auxiliaryPixelData.GetHeight());
598 texture.Upload(auxiliaryPixelData);
599 textureSet.SetTexture(1, texture);
600 mImpl->mRenderer.RegisterProperty(DevelImageVisual::Property::AUXILIARY_IMAGE_ALPHA,
601 AUXILIARY_IMAGE_ALPHA_NAME,
602 mAuxiliaryImageAlpha);
604 mImpl->mRenderer.SetTextures(textureSet);
606 // Register transform properties
607 mImpl->mTransform.RegisterUniforms(mImpl->mRenderer, Direction::LEFT_TO_RIGHT);
610 Geometry NPatchVisual::GetNinePatchGeometry(VisualFactoryCache::GeometryType subType)
612 Geometry geometry = mFactoryCache.GetGeometry(subType);
615 if(DALI_LIKELY(VisualFactoryCache::NINE_PATCH_GEOMETRY == subType))
617 geometry = CreateGridGeometry(Uint16Pair(3, 3));
619 else if(VisualFactoryCache::NINE_PATCH_BORDER_GEOMETRY == subType)
621 geometry = CreateBorderGeometry(Uint16Pair(3, 3));
623 mFactoryCache.SaveGeometry(subType, geometry);
628 Geometry NPatchVisual::CreateGridGeometry(Uint16Pair gridSize)
630 uint16_t gridWidth = gridSize.GetWidth();
631 uint16_t gridHeight = gridSize.GetHeight();
634 Vector<Vector2> vertices;
635 vertices.Reserve((gridWidth + 1) * (gridHeight + 1));
637 for(int y = 0; y < gridHeight + 1; ++y)
639 for(int x = 0; x < gridWidth + 1; ++x)
641 AddVertex(vertices, x, y);
646 Vector<unsigned short> indices;
647 indices.Reserve(gridWidth * gridHeight * 6);
649 unsigned int rowIdx = 0;
650 unsigned int nextRowIdx = gridWidth + 1;
651 for(int y = 0; y < gridHeight; ++y, ++nextRowIdx, ++rowIdx)
653 for(int x = 0; x < gridWidth; ++x, ++nextRowIdx, ++rowIdx)
655 AddQuadIndices(indices, rowIdx, nextRowIdx);
659 return GenerateGeometry(vertices, indices);
662 Geometry NPatchVisual::CreateBorderGeometry(Uint16Pair gridSize)
664 uint16_t gridWidth = gridSize.GetWidth();
665 uint16_t gridHeight = gridSize.GetHeight();
668 Vector<Vector2> vertices;
669 vertices.Reserve((gridWidth + 1) * (gridHeight + 1));
675 for(int x = 0; x < gridWidth + 1; ++x)
677 AddVertex(vertices, x, y);
681 for(; y < gridHeight - 1; ++y)
684 AddVertex(vertices, 0, y);
685 AddVertex(vertices, 1, y);
688 AddVertex(vertices, gridWidth - 1, y);
689 AddVertex(vertices, gridWidth, y);
693 for(; y < gridHeight + 1; ++y)
695 for(int x = 0; x < gridWidth + 1; ++x)
697 AddVertex(vertices, x, y);
702 Vector<unsigned short> indices;
703 indices.Reserve(gridWidth * gridHeight * 6);
706 unsigned int rowIdx = 0;
707 unsigned int nextRowIdx = gridWidth + 1;
708 for(int x = 0; x < gridWidth; ++x, ++nextRowIdx, ++rowIdx)
710 AddQuadIndices(indices, rowIdx, nextRowIdx);
715 rowIdx = gridWidth + 1;
716 nextRowIdx = (gridWidth + 1) * 2;
718 unsigned increment = gridWidth - 1;
723 AddQuadIndices(indices, rowIdx, nextRowIdx);
725 rowIdx = gridWidth * 2;
726 nextRowIdx = (gridWidth + 1) * 2 + 2;
728 AddQuadIndices(indices, rowIdx, nextRowIdx);
731 rowIdx = nextRowIdx - 2;
732 nextRowIdx = rowIdx + 4;
733 for(int y = 2; y < 2 * (gridHeight - 3); ++y, rowIdx += 2, nextRowIdx += 2)
735 AddQuadIndices(indices, rowIdx, nextRowIdx);
740 AddQuadIndices(indices, rowIdx, nextRowIdx);
743 nextRowIdx += gridWidth - 1;
745 AddQuadIndices(indices, rowIdx, nextRowIdx);
749 rowIdx = nextRowIdx - gridWidth + 1;
750 nextRowIdx = rowIdx + gridWidth + 1;
751 for(int x = 0; x < gridWidth; ++x, ++nextRowIdx, ++rowIdx)
753 AddQuadIndices(indices, rowIdx, nextRowIdx);
756 return GenerateGeometry(vertices, indices);
759 void NPatchVisual::SetResource()
761 const NPatchData* data;
762 if(mImpl->mRenderer && mLoader.GetNPatchData(mId, data))
764 Geometry geometry = CreateGeometry();
765 Shader shader = CreateShader();
767 mImpl->mRenderer.SetGeometry(geometry);
768 mImpl->mRenderer.SetShader(shader);
770 Actor actor = mPlacementActor.GetHandle();
773 ApplyTextureAndUniforms();
774 actor.AddRenderer(mImpl->mRenderer);
775 mPlacementActor.Reset();
777 // npatch loaded and ready to display
778 ResourceReady(Toolkit::Visual::ResourceStatus::READY);
783 void NPatchVisual::UploadComplete(bool loadSuccess, int32_t textureId, TextureSet textureSet, bool useAtlasing, const Vector4& atlasRect, bool preMultiplied)
785 EnablePreMultipliedAlpha(preMultiplied);
788 // Image loaded and ready to display
789 ResourceReady(Toolkit::Visual::ResourceStatus::FAILED);
792 if(mAuxiliaryPixelBuffer || !mAuxiliaryUrl.IsValid())
798 void NPatchVisual::LoadComplete(bool loadSuccess, Devel::PixelBuffer pixelBuffer, const VisualUrl& url, bool preMultiplied)
800 if(loadSuccess && url.GetUrl() == mAuxiliaryUrl.GetUrl())
802 mAuxiliaryPixelBuffer = pixelBuffer;
807 // Image loaded and ready to display
808 ResourceReady(Toolkit::Visual::ResourceStatus::FAILED);
812 } // namespace Internal
814 } // namespace Toolkit