DALI_TEST_EQUAL(2u, materials.size());
const MaterialDefinition materialGroundTruth[]{
{MaterialDefinition::ALBEDO | MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS |
+ MaterialDefinition::EMISSIVE | MaterialDefinition::OCCLUSION |
MaterialDefinition::NORMAL | MaterialDefinition::TRANSPARENCY | MaterialDefinition::GLTF_CHANNELS |
(0x80 << MaterialDefinition::ALPHA_CUTOFF_SHIFT),
0,
Vector4(1.f, .766f, .336f, 1.f),
+ Vector3(0.2, 0.1, 0.0),
1.f,
0.f,
+ 1.f,
{
{MaterialDefinition::ALBEDO,
{"AnimatedCube_BaseColor.png",
{MaterialDefinition::NORMAL,
{"AnimatedCube_BaseColor.png",
SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT)}},
+ {MaterialDefinition::OCCLUSION,
+ {"AnimatedCube_BaseColor.png",
+ SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT)}},
+ {MaterialDefinition::EMISSIVE,
+ {"AnimatedCube_BaseColor.png",
+ SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT)}},
}},
{MaterialDefinition::ALBEDO | MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS |
+ MaterialDefinition::EMISSIVE | MaterialDefinition::OCCLUSION |
MaterialDefinition::NORMAL | MaterialDefinition::GLTF_CHANNELS,
0,
Vector4(1.f, .766f, .336f, 1.f),
+ Vector3(0.2, 0.1, 0.0),
1.f,
0.f,
+ 1.f,
{
{MaterialDefinition::ALBEDO,
{"AnimatedCube_BaseColor.png",
{MaterialDefinition::NORMAL,
{"AnimatedCube_BaseColor.png",
SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT)}},
+ {MaterialDefinition::OCCLUSION,
+ {"AnimatedCube_BaseColor.png",
+ SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT)}},
+ {MaterialDefinition::EMISSIVE,
+ {"AnimatedCube_BaseColor.png",
+ SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT)}},
}},
};
namespace
{
-bool EndsWith(const std::string& str, const std::string& suffix) // ends_width() is C++20
-{
- return str.size() >= suffix.size() && str.substr(str.size() - suffix.size()).compare(suffix) == 0;
-}
-
MaterialDefinition& NewMaterialDefinition(ResourceBundle& resources)
{
resources.mMaterials.push_back({});
DALI_TEST_EQUAL(ps.shaderIdx, shaderIdx);
auto& shaderDef = ctx.resources.mShaders[shaderIdx].first;
- DALI_TEST_CHECK(EndsWith(shaderDef.mVertexShaderPath, ".vsh"));
- DALI_TEST_CHECK(EndsWith(shaderDef.mFragmentShaderPath, ".fsh"));
DALI_TEST_EQUAL(shaderDef.mRendererState, rendererState);
uint32_t definesUnmatched = shaderDef.mDefines.size();
namespace
{
const char* TEST_IMAGE_FILE_NAME = TEST_RESOURCE_DIR "/gallery-small-1.jpg";
-
-}
+const char* TEST_MASK_FILE_NAME = TEST_RESOURCE_DIR "/mask.png";
class TestObserver : public Dali::Toolkit::TextureUploadObserver
{
TextureSet mTextureSet;
};
+class TestObserverRemoveAndGenerateUrl : public TestObserver
+{
+public:
+ TestObserverRemoveAndGenerateUrl(TextureManager* textureManagerPtr)
+ : TestObserver(),
+ mTextureManagerPtr(textureManagerPtr)
+ {
+ }
+
+ virtual void LoadComplete(bool loadSuccess, TextureInformation textureInformation) override
+ {
+ if(textureInformation.returnType == TextureUploadObserver::ReturnType::TEXTURE)
+ {
+ mCompleteType = CompleteType::UPLOAD_COMPLETE;
+ }
+ else
+ {
+ mCompleteType = CompleteType::LOAD_COMPLETE;
+ }
+ mLoaded = loadSuccess;
+ mObserverCalled = true;
+ mTextureSet = textureInformation.textureSet;
+
+ // Remove during LoadComplete
+ mTextureManagerPtr->Remove(textureInformation.textureId, nullptr);
+
+ // ...And generate string which using texture id.
+ mGeneratedExternalUrl = mTextureManagerPtr->AddExternalTexture(mTextureSet);
+ }
+
+public:
+ std::string mGeneratedExternalUrl;
+
+protected:
+ TextureManager* mTextureManagerPtr; // Keep the pointer of texture manager.
+};
+
+} // namespace
+
int UtcTextureManagerRequestLoad(void)
{
ToolkitTestApplication application;
EncodedImageBuffer buffer1 = ConvertFileToEncodedImageBuffer(TEST_IMAGE_FILE_NAME);
EncodedImageBuffer buffer2 = ConvertFileToEncodedImageBuffer(TEST_IMAGE_FILE_NAME);
- std::string url1 = textureManager.AddExternalEncodedImageBuffer(buffer1);
- std::string url2 = textureManager.AddExternalEncodedImageBuffer(buffer1);
+ std::string url1 = textureManager.AddEncodedImageBuffer(buffer1);
+ std::string url2 = textureManager.AddEncodedImageBuffer(buffer1);
std::string url3 = VisualUrl::CreateBufferUrl(""); ///< Impossible Buffer URL. for coverage
// Check if same EncodedImageBuffer get same url
DALI_TEST_CHECK(url1 == url2);
// Reduce reference count
- textureManager.RemoveExternalEncodedImageBuffer(url1);
+ textureManager.RemoveEncodedImageBuffer(url1);
// Check whethere url1 still valid
DALI_TEST_CHECK(textureManager.GetEncodedImageBuffer(url1));
- url2 = textureManager.AddExternalEncodedImageBuffer(buffer2);
+ url2 = textureManager.AddEncodedImageBuffer(buffer2);
// Check if difference EncodedImageBuffer get difference url
DALI_TEST_CHECK(url1 != url2);
DALI_TEST_EQUALS(observer2.mObserverCalled, true, TEST_LOCATION);
DALI_TEST_EQUALS(observer2.mCompleteType, TestObserver::CompleteType::LOAD_COMPLETE, TEST_LOCATION);
- textureManager.RemoveExternalEncodedImageBuffer(url1);
- textureManager.RemoveExternalEncodedImageBuffer(url2);
+ textureManager.RemoveEncodedImageBuffer(url1);
+ textureManager.RemoveEncodedImageBuffer(url2);
// Now url1 and url2 is invalid type. mLoaded will return false
EncodedImageBuffer buffer1 = ConvertFileToEncodedImageBuffer(TEST_IMAGE_FILE_NAME);
EncodedImageBuffer buffer2 = ConvertFileToEncodedImageBuffer(TEST_IMAGE_FILE_NAME);
- std::string url1 = textureManager.AddExternalEncodedImageBuffer(buffer1);
- std::string url2 = textureManager.AddExternalEncodedImageBuffer(buffer1);
+ std::string url1 = textureManager.AddEncodedImageBuffer(buffer1);
+ std::string url2 = textureManager.AddEncodedImageBuffer(buffer1);
// Check if same EncodedImageBuffer get same url
DALI_TEST_CHECK(url1 == url2);
// Reduce reference count
- textureManager.RemoveExternalEncodedImageBuffer(url1);
+ textureManager.RemoveEncodedImageBuffer(url1);
// Check whethere url1 still valid
DALI_TEST_CHECK(textureManager.GetEncodedImageBuffer(url1));
// Reduce reference count
- textureManager.RemoveExternalEncodedImageBuffer(url1);
+ textureManager.RemoveEncodedImageBuffer(url1);
// Check whethere url1 is not valid anymore
DALI_TEST_CHECK(!textureManager.GetEncodedImageBuffer(url1));
textureManager.UseExternalResource(url1);
DALI_TEST_CHECK(!textureManager.GetEncodedImageBuffer(url1));
- url1 = textureManager.AddExternalEncodedImageBuffer(buffer1);
- // Check if difference EncodedImageBuffer get difference url
- // Previous EncodedImageBuffer was deleted, so we get new url even same buffer.
- DALI_TEST_CHECK(url1 != url2);
+ url1 = textureManager.AddEncodedImageBuffer(buffer1);
- url2 = textureManager.AddExternalEncodedImageBuffer(buffer2);
+ url2 = textureManager.AddEncodedImageBuffer(buffer2);
// Check if difference EncodedImageBuffer get difference url
DALI_TEST_CHECK(url1 != url2);
DALI_TEST_EQUALS(observer2.mCompleteType, TestObserver::CompleteType::LOAD_COMPLETE, TEST_LOCATION);
// Decrease each url's reference count.
- textureManager.RemoveExternalEncodedImageBuffer(url1);
- textureManager.RemoveExternalEncodedImageBuffer(url2);
+ textureManager.RemoveEncodedImageBuffer(url1);
+ textureManager.RemoveEncodedImageBuffer(url2);
// url1 buffer is still have 1 reference count because it is cached.
// But url2 not valid because it is not cached.
DALI_TEST_CHECK(!textureManager.GetEncodedImageBuffer(url2));
// Check url1 buffer have 1 reference count because it is cached.
- textureManager.RemoveExternalEncodedImageBuffer(url1);
+ textureManager.RemoveEncodedImageBuffer(url1);
DALI_TEST_CHECK(!textureManager.GetEncodedImageBuffer(url1));
END_TEST;
END_TEST;
}
+
+int UtcTextureManagerQueueRemoveDuringObserve(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline("UtcTextureManagerQueueRemoveDuringObserve");
+
+ TextureManager textureManager; // Create new texture manager
+
+ TestObserverRemoveAndGenerateUrl observer(&textureManager); // special observer for this UTC.
+
+ std::string filename(TEST_IMAGE_FILE_NAME);
+ auto preMultiply = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
+
+ TextureManager::TextureId textureId = textureManager.RequestLoad(
+ filename,
+ ImageDimensions(),
+ FittingMode::SCALE_TO_FILL,
+ SamplingMode::BOX_THEN_LINEAR,
+ TextureManager::UseAtlas::NO_ATLAS,
+ &observer,
+ true,
+ TextureManager::ReloadPolicy::CACHED,
+ preMultiply);
+
+ DALI_TEST_EQUALS(observer.mLoaded, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(observer.mObserverCalled, false, TEST_LOCATION);
+
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS(observer.mLoaded, true, TEST_LOCATION);
+ DALI_TEST_EQUALS(observer.mObserverCalled, true, TEST_LOCATION);
+ DALI_TEST_EQUALS(observer.mCompleteType, TestObserver::CompleteType::UPLOAD_COMPLETE, TEST_LOCATION);
+
+ tet_printf("loaded textureId is %d, generated url is %s\n", static_cast<int>(textureId), observer.mGeneratedExternalUrl.c_str());
+
+ DALI_TEST_CHECK(static_cast<int>(textureId) != std::stoi(VisualUrl::GetLocation(observer.mGeneratedExternalUrl))); // Check we don't reuse textureId during observe
+
+ // Decrease external texture reference count who observer created
+ textureManager.RemoveExternalTexture(observer.mGeneratedExternalUrl);
+
+ application.SendNotification();
+ application.Render();
+
+ END_TEST;
+}
+
+int UtcTextureManagerRemoveDuringApplyMasking(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline("UtcTextureManagerRemoveDuringApplyMasking");
+
+ TextureManager textureManager; // Create new texture manager
+
+ TestObserver observer1;
+ TestObserver observer2;
+
+ std::string filename(TEST_IMAGE_FILE_NAME);
+ std::string maskname(TEST_MASK_FILE_NAME);
+ TextureManager::MaskingDataPointer maskInfo = nullptr;
+ maskInfo.reset(new TextureManager::MaskingData());
+ maskInfo->mAlphaMaskUrl = maskname;
+ maskInfo->mAlphaMaskId = TextureManager::INVALID_TEXTURE_ID;
+ maskInfo->mCropToMask = true;
+ maskInfo->mContentScaleFactor = 1.0f;
+
+ auto textureId1(TextureManager::INVALID_TEXTURE_ID);
+ Vector4 atlasRect(0.f, 0.f, 1.f, 1.f);
+ Dali::ImageDimensions atlasRectSize(0, 0);
+ bool synchronousLoading(false);
+ bool atlasingStatus(false);
+ bool loadingStatus(false);
+ auto preMultiply = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
+ ImageAtlasManagerPtr atlasManager = nullptr;
+ Toolkit::AtlasUploadObserver* atlasUploadObserver = nullptr;
+
+ textureManager.LoadTexture(
+ filename,
+ ImageDimensions(),
+ FittingMode::SCALE_TO_FILL,
+ SamplingMode::BOX_THEN_LINEAR,
+ maskInfo,
+ synchronousLoading,
+ textureId1,
+ atlasRect,
+ atlasRectSize,
+ atlasingStatus,
+ loadingStatus,
+ WrapMode::DEFAULT,
+ WrapMode::DEFAULT,
+ &observer1,
+ atlasUploadObserver,
+ atlasManager,
+ true,
+ TextureManager::ReloadPolicy::CACHED,
+ preMultiply);
+
+ DALI_TEST_EQUALS(observer1.mLoaded, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(observer1.mObserverCalled, false, TEST_LOCATION);
+
+ application.SendNotification();
+ application.Render();
+
+ // Load image and mask image.
+ // Now, LoadState become MASK_APPLYING
+ DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(2), true, TEST_LOCATION);
+
+ tet_printf("Current textureId1:%d's state become MASK_APPLYING\n", static_cast<int>(textureId1));
+
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS(observer1.mLoaded, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(observer1.mObserverCalled, false, TEST_LOCATION);
+
+ // Remove current textureId1. and request new texture again.
+ textureManager.Remove(textureId1, &observer1);
+ auto textureId2 = textureManager.RequestLoad(
+ filename,
+ ImageDimensions(),
+ FittingMode::SCALE_TO_FILL,
+ SamplingMode::BOX_THEN_LINEAR,
+ TextureManager::UseAtlas::NO_ATLAS,
+ &observer2,
+ true, ///< orientationCorrection
+ TextureManager::ReloadPolicy::CACHED,
+ preMultiply,
+ synchronousLoading);
+
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS(observer1.mLoaded, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(observer1.mObserverCalled, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(observer2.mLoaded, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(observer2.mObserverCalled, false, TEST_LOCATION);
+
+ tet_printf("textureId1:%d removed and textureId2:%d requested\n", static_cast<int>(textureId1), static_cast<int>(textureId2));
+
+ // ApplyMask event come back, and do nothing.
+ // CAPTION : HARD-CODING.
+ {
+ textureManager.AsyncLoadComplete(textureId1, Dali::Devel::PixelBuffer());
+ textureManager.Remove(maskInfo->mAlphaMaskId, nullptr);
+ }
+
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS(observer1.mLoaded, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(observer1.mObserverCalled, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(observer2.mLoaded, false, TEST_LOCATION);
+ DALI_TEST_EQUALS(observer2.mObserverCalled, false, TEST_LOCATION);
+
+ // CAPTION : HARD-CODING.
+ {
+ textureManager.AsyncLoadComplete(textureId2, Dali::Devel::PixelBuffer());
+ textureManager.Remove(textureId2, &observer2);
+ }
+
+ DALI_TEST_EQUALS(observer2.mLoaded, false, TEST_LOCATION); ///< Note that we call AsyncLoadComplete hardly with empty pixelbuffer.
+ DALI_TEST_EQUALS(observer2.mObserverCalled, true, TEST_LOCATION);
+ DALI_TEST_EQUALS(observer2.mCompleteType, TestObserver::CompleteType::UPLOAD_COMPLETE, TEST_LOCATION);
+
+ END_TEST;
+}
\ No newline at end of file
DALI_TEST_EQUALS( VisualUrl::GIF, VisualUrl(".GiF").GetType(), TEST_LOCATION );
- // GIFs aren't N-patch
- DALI_TEST_EQUALS( VisualUrl::GIF, VisualUrl("foobar.9.gif").GetType(), TEST_LOCATION );
+ DALI_TEST_EQUALS( VisualUrl::N_PATCH, VisualUrl("foobar.9.gif").GetType(), TEST_LOCATION );
DALI_TEST_EQUALS( VisualUrl::REGULAR_IMAGE, VisualUrl("gif.png").GetType(), TEST_LOCATION );
DALI_TEST_EQUALS( VisualUrl::REGULAR_IMAGE, VisualUrl("gif.gif1").GetType(), TEST_LOCATION );
/*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include <dali/devel-api/adaptor-framework/vector-image-renderer.h>
#include <dali/public-api/object/base-object.h>
#include <dali/public-api/rendering/renderer.h>
+#include <sys/stat.h>
#include <toolkit-application.h>
#include <toolkit-event-thread-callback.h>
-#include <memory>
#include <cstring>
-#include <sys/stat.h>
+#include <memory>
namespace Dali
{
-
namespace Internal
{
-
namespace Adaptor
{
-
-class VectorImageRenderer: public Dali::BaseObject
+class VectorImageRenderer : public Dali::BaseObject
{
public:
-
VectorImageRenderer()
: mWidth(0),
mHeight(0),
return true;
}
- bool Rasterize(Dali::Devel::PixelBuffer& buffer, float scale)
+ Dali::Devel::PixelBuffer Rasterize(uint32_t width, uint32_t height)
{
- return mRasterizeSuccess;
+ if(mRasterizeSuccess)
+ {
+ Devel::PixelBuffer pixelBuffer = Devel::PixelBuffer::New(width, height, Dali::Pixel::RGBA8888);
+ return pixelBuffer;
+ }
+ return Dali::Devel::PixelBuffer();
}
void GetDefaultSize(uint32_t& width, uint32_t& height) const
{
- width = 100;
+ width = 100;
height = 100;
}
public:
-
uint32_t mWidth;
uint32_t mHeight;
bool mRasterizeSuccess;
};
-inline VectorImageRenderer& GetImplementation( Dali::VectorImageRenderer& renderer )
+inline VectorImageRenderer& GetImplementation(Dali::VectorImageRenderer& renderer)
{
- DALI_ASSERT_ALWAYS( renderer && "VectorImageRenderer handle is empty." );
+ DALI_ASSERT_ALWAYS(renderer && "VectorImageRenderer handle is empty.");
BaseObject& handle = renderer.GetBaseObject();
- return static_cast< Internal::Adaptor::VectorImageRenderer& >( handle );
+ return static_cast<Internal::Adaptor::VectorImageRenderer&>(handle);
}
-inline const VectorImageRenderer& GetImplementation( const Dali::VectorImageRenderer& renderer )
+inline const VectorImageRenderer& GetImplementation(const Dali::VectorImageRenderer& renderer)
{
- DALI_ASSERT_ALWAYS( renderer && "VectorImageRenderer handle is empty." );
+ DALI_ASSERT_ALWAYS(renderer && "VectorImageRenderer handle is empty.");
const BaseObject& handle = renderer.GetBaseObject();
- return static_cast< const Internal::Adaptor::VectorImageRenderer& >( handle );
+ return static_cast<const Internal::Adaptor::VectorImageRenderer&>(handle);
}
} // namespace Adaptor
} // namespace Internal
-
/********************************************************************************/
/********************************* PUBLIC CLASS *******************************/
/********************************************************************************/
{
Internal::Adaptor::VectorImageRenderer* imageRenderer = new Internal::Adaptor::VectorImageRenderer();
- return VectorImageRenderer( imageRenderer );
+ return VectorImageRenderer(imageRenderer);
}
VectorImageRenderer::VectorImageRenderer()
{
}
-VectorImageRenderer::VectorImageRenderer( Internal::Adaptor::VectorImageRenderer* internal )
-: BaseHandle( internal )
+VectorImageRenderer::VectorImageRenderer(Internal::Adaptor::VectorImageRenderer* internal)
+: BaseHandle(internal)
{
}
return Internal::Adaptor::GetImplementation(*this).Load(data, dpi);
}
-bool VectorImageRenderer::Rasterize(Dali::Devel::PixelBuffer& buffer, float scale)
+Dali::Devel::PixelBuffer VectorImageRenderer::Rasterize(uint32_t width, uint32_t height)
{
- return Internal::Adaptor::GetImplementation(*this).Rasterize(buffer, scale);
+ return Internal::Adaptor::GetImplementation(*this).Rasterize(width, height);
}
-void VectorImageRenderer::GetDefaultSize( uint32_t& width, uint32_t& height ) const
+void VectorImageRenderer::GetDefaultSize(uint32_t& width, uint32_t& height) const
{
- Internal::Adaptor::GetImplementation( *this ).GetDefaultSize( width, height );
+ Internal::Adaptor::GetImplementation(*this).GetDefaultSize(width, height);
}
} // namespace Dali
const char* TEST_IMAGE_FILE_NAME = "gallery_image_01.jpg";
const char* TEST_IMAGE_FILE_NAME2 = "gallery_image_02.jpg";
+// resolution: 1024*1024
const char* TEST_IMAGE_1 = TEST_RESOURCE_DIR "/TB-gloss.png";
const char* TEST_IMAGE_2 = TEST_RESOURCE_DIR "/tb-norm.png";
tet_infoline("Test load from a remote server.");
ToolkitTestApplication application;
- Toolkit::ImageView imageView;
- imageView = Toolkit::ImageView::New();
- imageView.SetImage("https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/check.svg");
- // Victor. Temporary (or permanent?) update as the url above seems not to work from time to time ...
- // imageView.SetImage("https://upload.wikimedia.org/wikipedia/commons/thumb/0/02/SVG_logo.svg/64px-SVG_logo.svg.png");
- imageView.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
- imageView.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
- imageView.SetProperty(Actor::Property::SIZE, Vector2(300, 300));
- imageView.SetProperty(Actor::Property::POSITION, Vector3(150.0f, 150.0f, 0.0f));
- application.GetScene().Add(imageView);
+ {
+ Toolkit::ImageView imageView;
+ imageView = Toolkit::ImageView::New();
+ imageView.SetImage("https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/check.svg");
+ imageView.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
+ imageView.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+ imageView.SetProperty(Actor::Property::SIZE, Vector2(300, 300));
+ imageView.SetProperty(Actor::Property::POSITION, Vector3(150.0f, 150.0f, 0.0f));
- DALI_TEST_CHECK(imageView);
+ application.GetScene().Add(imageView);
- DALI_TEST_EQUALS(imageView.GetRendererCount(), 0u, TEST_LOCATION);
+ DALI_TEST_CHECK(imageView);
- application.SendNotification();
+ DALI_TEST_EQUALS(imageView.GetRendererCount(), 0u, TEST_LOCATION);
- DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+ application.SendNotification();
- application.SendNotification();
- application.Render();
+ DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
- DALI_TEST_EQUALS(imageView.GetRendererCount(), 1u, TEST_LOCATION);
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS(imageView.GetRendererCount(), 1u, TEST_LOCATION);
+ }
+
+ // Without size set
+ {
+ Toolkit::ImageView imageView;
+ imageView = Toolkit::ImageView::New();
+ imageView.SetImage("https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/check.svg");
+ imageView.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
+ imageView.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+ imageView.SetProperty(Actor::Property::POSITION, Vector3(150.0f, 150.0f, 0.0f));
+
+ application.GetScene().Add(imageView);
+
+ DALI_TEST_CHECK(imageView);
+
+ DALI_TEST_EQUALS(imageView.GetRendererCount(), 0u, TEST_LOCATION);
+
+ application.SendNotification();
+
+ DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS(imageView.GetRendererCount(), 1u, TEST_LOCATION);
+ }
END_TEST;
}
{
ToolkitTestApplication application;
+ TestGlAbstraction& gl = application.GetGlAbstraction();
+ TraceCallStack& textureTrace = gl.GetTextureTrace();
+ textureTrace.Enable(true);
+
// Local svg file - invalid file path
{
gResourceReadySignalFired = false;
DALI_TEST_EQUALS(gResourceReadySignalFired, true, TEST_LOCATION);
DALI_TEST_EQUALS(imageView.IsResourceReady(), true, TEST_LOCATION);
DALI_TEST_EQUALS(imageView.GetVisualResourceStatus(ImageView::Property::IMAGE), Visual::ResourceStatus::FAILED, TEST_LOCATION);
+
+ // Should be shown a broken image
+ DALI_TEST_EQUALS(imageView.GetRendererCount(), 1u, TEST_LOCATION);
+ DALI_TEST_EQUALS(textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION);
+ }
+
+ // Local svg file - invalid file path without size set
+ {
+ gResourceReadySignalFired = false;
+ textureTrace.Reset();
+
+ ImageView imageView = ImageView::New(TEST_RESOURCE_DIR "/foo.svg");
+ imageView.ResourceReadySignal().Connect(&ResourceReadySignal);
+
+ DALI_TEST_EQUALS(imageView.IsResourceReady(), false, TEST_LOCATION);
+
+ application.GetScene().Add(imageView);
+
+ application.SendNotification();
+ application.Render(16);
+
+ DALI_TEST_EQUALS(gResourceReadySignalFired, true, TEST_LOCATION);
+ DALI_TEST_EQUALS(imageView.IsResourceReady(), true, TEST_LOCATION);
+ DALI_TEST_EQUALS(imageView.GetVisualResourceStatus(ImageView::Property::IMAGE), Visual::ResourceStatus::FAILED, TEST_LOCATION);
+
+ // Should be shown a broken image
+ DALI_TEST_EQUALS(imageView.GetRendererCount(), 1u, TEST_LOCATION);
+ DALI_TEST_EQUALS(textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION);
}
// Local svg file - invalid file
{
gResourceReadySignalFired = false;
+ textureTrace.Reset();
ImageView imageView = ImageView::New(TEST_RESOURCE_DIR "/invalid.svg");
imageView.SetProperty(Actor::Property::SIZE, Vector2(200.f, 200.f));
DALI_TEST_EQUALS(gResourceReadySignalFired, true, TEST_LOCATION);
DALI_TEST_EQUALS(imageView.IsResourceReady(), true, TEST_LOCATION);
DALI_TEST_EQUALS(imageView.GetVisualResourceStatus(ImageView::Property::IMAGE), Visual::ResourceStatus::FAILED, TEST_LOCATION);
+
+ // Should be shown a broken image
+ DALI_TEST_EQUALS(imageView.GetRendererCount(), 1u, TEST_LOCATION);
+ DALI_TEST_EQUALS(textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION);
}
// Remote svg file
{
gResourceReadySignalFired = false;
+ textureTrace.Reset();
ImageView imageView = ImageView::New("https://bar.org/foobar.svg");
imageView.SetProperty(Actor::Property::SIZE, Vector2(200.f, 200.f));
DALI_TEST_EQUALS(gResourceReadySignalFired, true, TEST_LOCATION);
DALI_TEST_EQUALS(imageView.IsResourceReady(), true, TEST_LOCATION);
DALI_TEST_EQUALS(imageView.GetVisualResourceStatus(ImageView::Property::IMAGE), Visual::ResourceStatus::FAILED, TEST_LOCATION);
+
+ // Should be shown a broken image
+ DALI_TEST_EQUALS(imageView.GetRendererCount(), 1u, TEST_LOCATION);
+ DALI_TEST_EQUALS(textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION);
+ }
+
+ // Remote svg file without size set
+ {
+ gResourceReadySignalFired = false;
+ textureTrace.Reset();
+
+ ImageView imageView = ImageView::New("https://bar.org/foobar.svg");
+ imageView.ResourceReadySignal().Connect(&ResourceReadySignal);
+
+ DALI_TEST_EQUALS(imageView.IsResourceReady(), false, TEST_LOCATION);
+
+ application.GetScene().Add(imageView);
+
+ application.SendNotification();
+
+ // loading started, this waits for the loader thread
+ DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+
+ application.SendNotification();
+ application.Render(16);
+
+ DALI_TEST_EQUALS(gResourceReadySignalFired, true, TEST_LOCATION);
+ DALI_TEST_EQUALS(imageView.IsResourceReady(), true, TEST_LOCATION);
+ DALI_TEST_EQUALS(imageView.GetVisualResourceStatus(ImageView::Property::IMAGE), Visual::ResourceStatus::FAILED, TEST_LOCATION);
+
+ // Should be shown a broken image
+ DALI_TEST_EQUALS(imageView.GetRendererCount(), 1u, TEST_LOCATION);
+ DALI_TEST_EQUALS(textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION);
}
END_TEST;
gResourceReadySignalFired = false;
- ImageView imageView = ImageView::New(TEST_RESOURCE_DIR "/svg1.svg");
+ TestGlAbstraction& gl = application.GetGlAbstraction();
+ TraceCallStack& textureTrace = gl.GetTextureTrace();
+ textureTrace.Enable(true);
+
+ ImageView imageView = ImageView::New(TEST_RESOURCE_DIR "/invalid1.svg");
imageView.SetProperty(Actor::Property::SIZE, Vector2(200.f, 200.f));
imageView.ResourceReadySignal().Connect(&ResourceReadySignal);
DALI_TEST_EQUALS(gResourceReadySignalFired, true, TEST_LOCATION);
DALI_TEST_EQUALS(imageView.IsResourceReady(), true, TEST_LOCATION);
- DALI_TEST_EQUALS(imageView.GetVisualResourceStatus(ImageView::Property::IMAGE), Visual::ResourceStatus::READY, TEST_LOCATION);
-
- // Reset flag
- gResourceReadySignalFired = false;
-
- // Change size
- imageView.SetProperty(Actor::Property::SIZE, Vector2(0.f, 0.f));
-
- application.SendNotification();
-
- // rasterization started, this waits for the rasterize thread
- DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
-
- application.SendNotification();
- application.Render(16);
-
- DALI_TEST_EQUALS(gResourceReadySignalFired, true, TEST_LOCATION);
- DALI_TEST_EQUALS(imageView.IsResourceReady(), true, TEST_LOCATION);
- // Fail to rasterize because the size is 0.
DALI_TEST_EQUALS(imageView.GetVisualResourceStatus(ImageView::Property::IMAGE), Visual::ResourceStatus::FAILED, TEST_LOCATION);
+ // Should be shown a broken image
+ DALI_TEST_EQUALS(imageView.GetRendererCount(), 1u, TEST_LOCATION);
+ DALI_TEST_EQUALS(textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION);
+
END_TEST;
}
}
END_TEST;
}
+
int UtcDaliImageViewImageLoadFailure01(void)
{
ToolkitTestApplication application;
else if(control.GetVisualResourceStatus(ImageView::Property::IMAGE) == Visual::ResourceStatus::FAILED)
{
// Make the resource ready immediately
- control[ImageView::Property::IMAGE] = TEST_RESOURCE_DIR "/svg1.svg";
+ control[ImageView::Property::IMAGE] = gImage_600_RGB;
}
}
ImageView gImageView1;
ImageView gImageView2;
ImageView gImageView3;
+ImageView gImageView4;
void OnResourceReadySignal03(Control control)
{
gResourceReadySignalCounter++;
}
+int gResourceReadySignal04ComesOrder = 0;
+
+void OnResourceReadySignal04(Control control)
+{
+ gResourceReadySignalCounter++;
+ tet_printf("rc %d\n", gResourceReadySignalCounter);
+ if(gResourceReadySignalCounter == 1)
+ {
+ auto scene = gImageView1.GetParent();
+
+ // Request load something
+ // We hope this request result is return later than gImageView2.
+ gImageView3 = ImageView::New(TEST_IMAGE_1);
+ gImageView3.ResourceReadySignal().Connect(&OnResourceReadySignal04);
+ scene.Add(gImageView3);
+ gImageView4 = ImageView::New(TEST_IMAGE_2);
+ gImageView4.ResourceReadySignal().Connect(&OnResourceReadySignal04);
+ scene.Add(gImageView4);
+
+ if(control == gImageView1)
+ {
+ gResourceReadySignal04ComesOrder = 1;
+ }
+ else
+ {
+ gResourceReadySignal04ComesOrder = 2;
+ }
+ }
+ if(gResourceReadySignalCounter == 2)
+ {
+ if(gResourceReadySignal04ComesOrder == 1 && control == gImageView2)
+ {
+ // Scene off first one.
+ gImageView1.Unparent();
+
+ // Scene off second one.
+ gImageView2.Unparent();
+ }
+ else if(gResourceReadySignal04ComesOrder == 2 && control == gImageView1)
+ {
+ // Scene off first one.
+ gImageView2.Unparent();
+
+ // Scene off second one.
+ gImageView1.Unparent();
+ }
+ else
+ {
+ // We can't check that this utc fail case. just pass always when we come here.
+ gResourceReadySignal04ComesOrder = -1;
+ }
+
+ // If we don't seperate index of FreeList area
+ // and if we don't queue remove during obversing,
+ // cache index become something invalid data.
+ // In this case, some strange observer can be called.
+ // For example, gImageView4.LoadComplete will be called.
+ }
+}
+
} // namespace
int UtcDaliImageViewSetImageOnResourceReadySignal01(void)
DALI_TEST_EQUALS(imageView.IsResourceReady(), true, TEST_LOCATION);
+ // Create a new ImageView to cache the image
+ ImageView imageView1 = ImageView::New(gImage_600_RGB);
+ application.GetScene().Add(imageView1);
+
+ DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+
+ application.SendNotification();
+ application.Render();
+
// Reset count
gResourceReadySignalCounter = 0;
END_TEST;
}
+
+int UtcDaliImageViewSetImageOnResourceReadySignal04(void)
+{
+ tet_infoline("Test texturemanager's remove queue works well within signal handler.");
+
+ ToolkitTestApplication application;
+
+ gResourceReadySignalCounter = 0;
+ gResourceReadySignal04ComesOrder = 0;
+
+ gImageView1 = ImageView::New("invalid.jpg"); // request invalid image, to make loading failed fast.
+ gImageView1.ResourceReadySignal().Connect(&OnResourceReadySignal04);
+ application.GetScene().Add(gImageView1);
+
+ gImageView2 = ImageView::New("invalid.png"); // request invalid image, to make loading failed fast.
+ gImageView2.ResourceReadySignal().Connect(&OnResourceReadySignal04);
+ application.GetScene().Add(gImageView2);
+
+ application.SendNotification();
+ application.Render();
+
+ tet_infoline("Try to load 2 invalid image");
+
+ DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(2), true, TEST_LOCATION);
+ DALI_TEST_EQUALS(gResourceReadySignalCounter, 2, TEST_LOCATION);
+
+ tet_infoline("load done");
+
+ // We can test this UTC only if gImageView1 and gImageView2 loaded done.
+ if(gResourceReadySignal04ComesOrder == -1)
+ {
+ tet_infoline("Bad news.. gImageView3 or gImageView4 loaded faster than others. just skip this UTC");
+ }
+ else
+ {
+ // gImageView3 and gImageView4 load must not be successed yet.
+ DALI_TEST_EQUALS(gImageView3.GetRendererCount(), 0u, TEST_LOCATION);
+ DALI_TEST_EQUALS(gImageView4.GetRendererCount(), 0u, TEST_LOCATION);
+
+ application.SendNotification();
+ application.Render();
+
+ tet_infoline("Try to load 2 valid image");
+
+ DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(2), true, TEST_LOCATION);
+ DALI_TEST_EQUALS(gResourceReadySignalCounter, 4, TEST_LOCATION);
+
+ tet_infoline("load done");
+
+ // gImageView3 and gImageView4 load must be successed now.
+ DALI_TEST_EQUALS(gImageView3.GetRendererAt(0).GetTextures().GetTextureCount(), 1u, TEST_LOCATION);
+ DALI_TEST_EQUALS(gImageView4.GetRendererAt(0).GetTextures().GetTextureCount(), 1u, TEST_LOCATION);
+ }
+
+ END_TEST;
+}
DALI_TEST_CHECK(manager.GetCurrentFocusActor() == second);
END_TEST;
+}
+
+int UtcDaliKeyboardFocusManagerFocusFinderRootActor(void)
+{
+ ToolkitTestApplication application;
+
+ tet_infoline(" UtcDaliKeyboardFocusManagerFocusFinderRootActor");
+
+ // Register Type
+ TypeInfo type;
+ type = TypeRegistry::Get().GetTypeInfo("KeyboardFocusManager");
+ DALI_TEST_CHECK(type);
+ BaseHandle handle = type.CreateInstance();
+ DALI_TEST_CHECK(handle);
+
+ KeyboardFocusManager manager = KeyboardFocusManager::Get();
+ DALI_TEST_CHECK(manager);
+
+ bool focusChangedSignalVerified = false;
+ FocusChangedCallback focusChangedCallback(focusChangedSignalVerified);
+ manager.FocusChangedSignal().Connect(&focusChangedCallback, &FocusChangedCallback::Callback);
+
+ PushButton button1 = PushButton::New();
+ PushButton button2 = PushButton::New();
+
+ button1.SetProperty(Actor::Property::SIZE, Vector2(50, 50));
+ button2.SetProperty(Actor::Property::SIZE, Vector2(50, 50));
+
+ button1.SetProperty(Actor::Property::KEYBOARD_FOCUSABLE, true);
+ button2.SetProperty(Actor::Property::KEYBOARD_FOCUSABLE, true);
+
+ application.GetScene().Add(button1);
+ application.GetScene().Add(button2);
+
+ Actor actor = Actor::New();
+ actor.SetProperty(Actor::Property::KEYBOARD_FOCUSABLE, true);
+ application.GetScene().Add(actor);
+
+ PushButton buttonA = PushButton::New();
+ PushButton buttonB = PushButton::New();
+
+ buttonA.SetProperty(Actor::Property::SIZE, Vector2(50, 50));
+ buttonB.SetProperty(Actor::Property::SIZE, Vector2(50, 50));
+
+ buttonA.SetProperty(Actor::Property::KEYBOARD_FOCUSABLE, true);
+ buttonB.SetProperty(Actor::Property::KEYBOARD_FOCUSABLE, true);
+
+ actor.Add(buttonA);
+ actor.Add(buttonB);
+
+ // set position
+ // button1 -- button2
+ button1.SetProperty(Actor::Property::POSITION, Vector2(0.0f, 0.0f));
+ button2.SetProperty(Actor::Property::POSITION, Vector2(100.0f, 0.0f));
+ button1.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+ button2.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+
+ // buttonA -- buttonB
+ buttonA.SetProperty(Actor::Property::POSITION, Vector2(0.0f, 50.0f));
+ buttonB.SetProperty(Actor::Property::POSITION, Vector2(100.0f, 50.0f));
+ buttonA.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+ buttonB.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+
+ // flush the queue and render once
+ application.SendNotification();
+ application.Render();
+
+ // Set the focus to the button1
+ // [button1] -- button2
+ DALI_TEST_CHECK(manager.SetCurrentFocusActor(button1) == true);
+ DALI_TEST_CHECK(manager.GetCurrentFocusActor() == button1);
+ DALI_TEST_CHECK(focusChangedCallback.mSignalVerified);
+ DALI_TEST_CHECK(focusChangedCallback.mOriginalFocusedActor == Actor());
+ DALI_TEST_CHECK(focusChangedCallback.mCurrentFocusedActor == button1);
+ focusChangedCallback.Reset();
+
+ // without set the navigation properties, but we can focus move
+ // enable the default algorithm
+ Dali::Toolkit::DevelKeyboardFocusManager::EnableDefaultAlgorithm(manager, true);
+ DALI_TEST_CHECK(Dali::Toolkit::DevelKeyboardFocusManager::IsDefaultAlgorithmEnabled(manager));
+
+ // Move the focus towards right
+ // button1 -- [button2]
+ DALI_TEST_CHECK(manager.MoveFocus(Control::KeyboardFocus::RIGHT) == true);
+
+ // Confirm whether focus is moved to button2
+ DALI_TEST_EQUALS(button2.GetProperty<int>(DevelControl::Property::STATE), (int)DevelControl::FOCUSED, TEST_LOCATION);
+ DALI_TEST_CHECK(focusChangedCallback.mSignalVerified);
+ DALI_TEST_CHECK(focusChangedCallback.mOriginalFocusedActor == button1);
+ DALI_TEST_CHECK(focusChangedCallback.mCurrentFocusedActor == button2);
+ focusChangedCallback.Reset();
+
+ // Clears focus.
+ manager.ClearFocus();
+
+ // There is no actor focused.
+ // button1 -- button2
+ // buttonA -- buttonB
+ DALI_TEST_CHECK(manager.GetCurrentFocusActor() == Actor());
+
+ // Sets the actor to root.
+ Dali::Toolkit::DevelKeyboardFocusManager::SetFocusFinderRootActor(manager, actor);
+
+ // Move the focus towards right
+ // [buttonA] -- buttonB
+ DALI_TEST_CHECK(manager.MoveFocus(Control::KeyboardFocus::RIGHT) == true);
+
+ // Confirm whether focus is moved to buttonA
+ // Because the root is an actor, the focus is moved to buttonA, a child of the actor.
+ DALI_TEST_EQUALS(buttonA.GetProperty<int>(DevelControl::Property::STATE), (int)DevelControl::FOCUSED, TEST_LOCATION);
+ DALI_TEST_CHECK(focusChangedCallback.mSignalVerified);
+ DALI_TEST_CHECK(focusChangedCallback.mOriginalFocusedActor == Actor());
+ DALI_TEST_CHECK(focusChangedCallback.mCurrentFocusedActor == buttonA);
+ focusChangedCallback.Reset();
+
+
+ // Move the focus towards right, The focus move will success.
+ // buttonA -- [buttonB]
+ DALI_TEST_CHECK(manager.MoveFocus(Control::KeyboardFocus::RIGHT) == true);
+ // Confirm whether focus is moved to buttonB
+ DALI_TEST_EQUALS(buttonB.GetProperty<int>(DevelControl::Property::STATE), (int)DevelControl::FOCUSED, TEST_LOCATION);
+ DALI_TEST_CHECK(focusChangedCallback.mSignalVerified);
+ DALI_TEST_CHECK(focusChangedCallback.mOriginalFocusedActor == buttonA);
+ DALI_TEST_CHECK(focusChangedCallback.mCurrentFocusedActor == buttonB);
+ focusChangedCallback.Reset();
+
+ // reset
+ Dali::Toolkit::DevelKeyboardFocusManager::ResetFocusFinderRootActor(manager);
+
+ END_TEST;
}
\ No newline at end of file
Ref<gltf2::Texture> mTexture;
uint32_t mTexCoord = 0;
float mScale = 1.f;
+ float mStrength = 1.f;
operator bool() const
{
--- /dev/null
+#version 300 es
+
+#ifdef HIGHP
+ precision highp float;
+#else
+ precision mediump float;
+#endif
+
+#ifdef THREE_TEX
+#ifdef GLTF_CHANNELS
+// https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#pbrmetallicroughnessmetallicroughnesstexture
+#define METALLIC b
+#define ROUGHNESS g
+#else //GLTF_CHANNELS
+#define METALLIC r
+#define ROUGHNESS a
+#endif //GLTF_CHANNELS
+#endif //THREE_TEX
+
+#ifdef THREE_TEX
+ uniform sampler2D sAlbedoAlpha;
+ uniform sampler2D sMetalRoughness;
+ uniform sampler2D sNormal;
+
+#ifdef ALPHA_TEST
+ uniform float uAlphaThreshold;
+#endif //ALPHA_TEST
+
+#else
+ uniform sampler2D sAlbedoMetal;
+ uniform sampler2D sNormalRoughness;
+#endif
+
+#ifdef OCCLUSION
+ uniform sampler2D sOcclusion;
+ uniform float uOcclusionStrength;
+#endif
+
+#ifdef EMISSIVE
+ uniform sampler2D sEmissive;
+ uniform vec3 uEmissiveFactor;
+#endif
+
+uniform samplerCube sDiffuse;
+uniform samplerCube sSpecular;
+
+// Number of mip map levels in the texture
+uniform float uMaxLOD;
+
+// Transformation matrix of the cubemap texture
+uniform mat4 uCubeMatrix;
+
+uniform vec4 uColor;
+uniform float uMetallicFactor;
+uniform float uRoughnessFactor;
+
+//IBL Light intensity
+uniform float uIblIntensity;
+
+// TODO: Multiple texture coordinate will be supported.
+in vec2 vUV;
+in vec3 vNormal;
+in vec3 vTangent;
+in vec3 vViewVec;
+
+out vec4 FragColor;
+
+// Functions for BRDF calculation come from
+// https://www.unrealengine.com/blog/physically-based-shading-on-mobile
+// Based on the paper by Dimitar Lazarov
+// http://blog.selfshadow.com/publications/s2013-shading-course/lazarov/s2013_pbs_black_ops_2_notes.pdf
+vec3 EnvBRDFApprox( vec3 SpecularColor, float Roughness, float NoV )
+{
+ const vec4 c0 = vec4( -1.0, -0.0275, -0.572, 0.022 );
+ const vec4 c1 = vec4( 1.0, 0.0425, 1.04, -0.04 );
+ vec4 r = Roughness * c0 + c1;
+ float a004 = min( r.x * r.x, exp2( -9.28 * NoV ) ) * r.x + r.y;
+ vec2 AB = vec2( -1.04, 1.04 ) * a004 + r.zw;
+
+ return SpecularColor * AB.x + AB.y;
+}
+
+void main()
+{
+ // We get information from the maps (albedo, normal map, roughness, metalness
+ // I access the maps in the order they will be used
+#ifdef THREE_TEX
+ vec4 albedoAlpha = texture(sAlbedoAlpha, vUV.st);
+ float alpha = albedoAlpha.a;
+#ifdef ALPHA_TEST
+ if (alpha <= uAlphaThreshold)
+ {
+ discard;
+ }
+#endif //ALPHA_TEST
+ vec3 albedoColor = albedoAlpha.rgb * uColor.rgb;
+
+ vec4 metalRoughness = texture(sMetalRoughness, vUV.st);
+ float metallic = metalRoughness.METALLIC * uMetallicFactor;
+ float roughness = metalRoughness.ROUGHNESS * uRoughnessFactor;
+
+ vec3 normalMap = texture(sNormal, vUV.st).rgb;
+#else //THREE_TEX
+ vec4 albedoMetal = texture(sAlbedoMetal, vUV.st);
+ vec3 albedoColor = albedoMetal.rgb * uColor.rgb;
+ float metallic = albedoMetal.a * uMetallicFactor;
+
+ vec4 normalRoughness = texture(sNormalRoughness, vUV.st);
+ vec3 normalMap = normalRoughness.rgb;
+ float roughness = normalRoughness.a * uRoughnessFactor;
+#endif
+ //Normalize vectors
+ vec3 normal = normalize(vNormal);
+ vec3 tangent = normalize(vTangent);
+
+ // NOTE: normal and tangent have to be orthogonal for the result of the cross()
+ // product to be a unit vector. We might find that we need to normalize().
+ vec3 bitangent = cross(normal, tangent);
+
+ vec3 viewVec = normalize(vViewVec);
+
+ // Create Inverse Local to world matrix
+ mat3 vInvTBN = mat3(tangent, bitangent, normal);
+
+ // Get normal map info in world space
+ normalMap = normalize(normalMap - 0.5);
+ vec3 newNormal = vInvTBN * normalMap.rgb;
+
+ // Calculate normal dot view vector
+ float NoV = max(dot(newNormal, -viewVec), 0.0);
+
+ // Reflect vector
+ vec3 reflectionVec = reflect(viewVec, newNormal);
+
+ //transform it now to environment coordinates (used when the environment rotates)
+ vec3 reflecCube = (uCubeMatrix * vec4( reflectionVec, 0.0 ) ).xyz;
+ reflecCube = normalize( reflecCube );
+
+ //transform it now to environment coordinates
+ vec3 normalCube = ( uCubeMatrix * vec4( newNormal, 0.0 ) ).xyz;
+ normalCube = normalize( normalCube );
+
+ // Get irradiance from diffuse cubemap
+ vec3 irradiance = texture( sDiffuse, normalCube ).rgb;
+
+ // Access reflection color using roughness value
+ float finalLod = mix( 0.0, uMaxLOD - 2.0, roughness);
+ vec3 reflectionColor = textureLod(sSpecular, reflecCube, finalLod).rgb;
+
+ // We are supposed to be using DielectricColor (0.04) of a plastic (almost everything)
+ // http://blog.selfshadow.com/publications/s2014-shading-course/hoffman/s2014_pbs_physics_math_slides.pdf
+ // however that seems to prevent achieving very dark tones (i.e. get dark gray blacks).
+ vec3 DiffuseColor = albedoColor - albedoColor * metallic; // 1 mad
+ vec3 SpecularColor = mix( vec3(0.04), albedoColor, metallic); // 2 mad
+
+ // Calculate specular color using Magic Function (takes original roughness and normal dot view).
+ vec3 specColor = reflectionColor.rgb * EnvBRDFApprox(SpecularColor, roughness, NoV );
+
+ // Multiply the result by albedo texture and do energy conservation
+ vec3 diffuseColor = irradiance * DiffuseColor;
+
+ // Final color is the sum of the diffuse and specular term
+ vec3 finalColor = diffuseColor + specColor;
+
+ finalColor = sqrt( finalColor ) * uIblIntensity;
+
+
+#ifdef OCCLUSION
+ float ao = texture(sOcclusion, vUV.st).r;
+ finalColor = mix( finalColor, finalColor * ao, uOcclusionStrength );
+#endif
+
+#ifdef EMISSIVE
+ vec3 emissive = texture( sEmissive, vUV.st ).rgb * uEmissiveFactor;
+ finalColor += emissive;
+#endif
+
+#ifdef THREE_TEX
+ FragColor = vec4( finalColor, alpha );
+#else //THREE_TEX
+ FragColor = vec4( finalColor, 1.0 );
+#endif //THREE_TEX
+}
--- /dev/null
+#version 300 es
+
+#ifdef HIGHP
+ precision highp float;
+#else
+ precision mediump float;
+#endif
+
+in vec3 aPosition;
+in vec2 aTexCoord;
+in vec3 aNormal;
+in vec3 aTangent;
+
+#ifdef MORPH
+ uniform sampler2D sBlendShapeGeometry;
+#endif
+
+out vec2 vUV;
+out vec3 vNormal;
+out vec3 vTangent;
+out vec3 vViewVec;
+
+uniform highp mat4 uMvpMatrix;
+uniform highp mat4 uViewMatrix;
+uniform mat3 uNormalMatrix;
+uniform mat4 uModelMatrix;
+uniform mat4 uModelView;
+uniform mat4 uProjection;
+
+#ifdef SKINNING
+ in vec4 aJoints;
+ in vec4 aWeights;
+ #define MAX_BONES 64
+ uniform mat4 uBone[MAX_BONES];
+#endif
+
+#ifdef MORPH
+#define MAX_BLEND_SHAPE_NUMBER 128
+uniform int uNumberOfBlendShapes; ///< Total number of blend shapes loaded.
+uniform float uBlendShapeWeight[MAX_BLEND_SHAPE_NUMBER]; ///< The weight of each blend shape.
+#ifdef MORPH_VERSION_2_0
+uniform float uBlendShapeUnnormalizeFactor; ///< Factor used to unnormalize the geometry of the blend shape.
+#else
+uniform float uBlendShapeUnnormalizeFactor[MAX_BLEND_SHAPE_NUMBER]; ///< Factor used to unnormalize the geometry of the blend shape.
+#endif
+uniform int uBlendShapeComponentSize; ///< The size in the texture of either the vertices, normals or tangents. Used to calculate the offset to address them.
+#endif
+
+void main()
+{
+ vec4 position = vec4(aPosition, 1.0);
+ vec3 normal = aNormal;
+ vec3 tangent = aTangent;
+
+#ifdef MORPH
+ int width = textureSize( sBlendShapeGeometry, 0 ).x;
+
+ int blendShapeBufferOffset = 0;
+ for( int index = 0; index < uNumberOfBlendShapes; ++index )
+ {
+#ifdef MORPH_POSITION
+ // Calculate the index to retrieve the geometry from the texture.
+ int vertexId = gl_VertexID + blendShapeBufferOffset;
+ int x = vertexId % width;
+ int y = vertexId / width;
+
+ vec3 diff = vec3(0.0);
+ // Retrieves the blend shape geometry from the texture, unnormalizes it and multiply by the weight.
+ if( 0.0 != uBlendShapeWeight[index] )
+ {
+#ifdef MORPH_VERSION_2_0
+ float unnormalizeFactor = uBlendShapeUnnormalizeFactor;
+#else
+ float unnormalizeFactor = uBlendShapeUnnormalizeFactor[index];
+#endif
+
+ diff = uBlendShapeWeight[index] * unnormalizeFactor * ( texelFetch( sBlendShapeGeometry, ivec2(x, y), 0 ).xyz - 0.5 );
+ }
+
+ position.xyz += diff;
+
+ blendShapeBufferOffset += uBlendShapeComponentSize;
+#endif
+
+#ifdef MORPH_NORMAL
+ // Calculate the index to retrieve the normal from the texture.
+ vertexId = gl_VertexID + blendShapeBufferOffset;
+ x = vertexId % width;
+ y = vertexId / width;
+
+ // Retrieves the blend shape normal from the texture, unnormalizes it and multiply by the weight.
+ if( 0.0 != uBlendShapeWeight[index] )
+ {
+ diff = uBlendShapeWeight[index] * 2.0 * ( texelFetch( sBlendShapeGeometry, ivec2(x, y), 0 ).xyz - 0.5 );
+ }
+
+ normal += diff.xyz;
+
+ blendShapeBufferOffset += uBlendShapeComponentSize;
+#endif
+
+#ifdef MORPH_TANGENT
+ // Calculate the index to retrieve the tangent from the texture.
+ vertexId = gl_VertexID + blendShapeBufferOffset;
+ x = vertexId % width;
+ y = vertexId / width;
+
+ // Retrieves the blend shape tangent from the texture, unnormalizes it and multiply by the weight.
+ if( 0.0 != uBlendShapeWeight[index] )
+ {
+ diff = uBlendShapeWeight[index] * 2.0 * ( texelFetch( sBlendShapeGeometry, ivec2(x, y), 0 ).xyz - 0.5 );
+ }
+
+ tangent += diff.xyz;
+
+ blendShapeBufferOffset += uBlendShapeComponentSize;
+#endif
+ }
+
+#endif
+
+#ifdef SKINNING
+ mat4 bone = uBone[int(aJoints.x)] * aWeights.x +
+ uBone[int(aJoints.y)] * aWeights.y +
+ uBone[int(aJoints.z)] * aWeights.z +
+ uBone[int(aJoints.w)] * aWeights.w;
+ position = bone * position;
+ normal = (bone * vec4(normal, 0.0)).xyz;
+ tangent = (bone * vec4(tangent, 0.0)).xyz;
+#endif
+
+ vec4 vPosition = uModelMatrix * position;
+
+ vNormal = normalize(uNormalMatrix * normal);
+
+ vTangent = normalize(uNormalMatrix * tangent);
+
+
+ vec4 viewPosition = uViewMatrix * vPosition;
+ gl_Position = uProjection * viewPosition;
+
+#ifdef FLIP_V
+ vUV = vec2(aTexCoord.x, 1.0 - aTexCoord.y);
+#else
+ vUV = aTexCoord;
+#endif
+
+ vViewVec = viewPosition.xyz;
+}
const auto TEXURE_INFO_READER = std::move(js::Reader<gt::TextureInfo>()
.Register(*js::MakeProperty("index", gt::RefReader<gt::Document>::Read<gt::Texture, >::Document::mTextures>, >::TextureInfo::mTexture))
.Register(*js::MakeProperty("texCoord", js::Read::Number<uint32_t>, >::TextureInfo::mTexCoord))
- .Register(*js::MakeProperty("scale", js::Read::Number<float>, >::TextureInfo::mScale)));
+ .Register(*js::MakeProperty("scale", js::Read::Number<float>, >::TextureInfo::mScale))
+ .Register(*js::MakeProperty("strength", js::Read::Number<float>, >::TextureInfo::mStrength)));
const auto MATERIAL_PBR_READER = std::move(js::Reader<gt::Material::Pbr>()
.Register(*js::MakeProperty("baseColorFactor", gt::ReadDaliVector<Vector4>, >::Material::Pbr::mBaseColorFactor))
matDef.mColor = pbr.mBaseColorFactor;
- matDef.mTextureStages.reserve(!!pbr.mBaseColorTexture + !!pbr.mMetallicRoughnessTexture + !!m.mNormalTexture);
+ matDef.mTextureStages.reserve(!!pbr.mBaseColorTexture + !!pbr.mMetallicRoughnessTexture + !!m.mNormalTexture + !!m.mOcclusionTexture + !!m.mEmissiveTexture);
if(pbr.mBaseColorTexture)
{
const auto semantic = MaterialDefinition::ALBEDO;
}
// TODO: handle doubleSided
+ if(m.mOcclusionTexture)
+ {
+ const auto semantic = MaterialDefinition::OCCLUSION;
+ matDef.mTextureStages.push_back({semantic, ConvertTextureInfo(m.mOcclusionTexture)});
+ // TODO: and there had better be one
+ matDef.mFlags |= semantic;
+ matDef.mOcclusionStrength = m.mOcclusionTexture.mStrength;
+ }
+
+ if(m.mEmissiveTexture)
+ {
+ const auto semantic = MaterialDefinition::EMISSIVE;
+ matDef.mTextureStages.push_back({semantic, ConvertTextureInfo(m.mEmissiveTexture)});
+ // TODO: and there had better be one
+ matDef.mFlags |= semantic;
+ matDef.mEmissiveFactor = m.mEmissiveFactor;
+ }
outMaterials.emplace_back(std::move(matDef), TextureSet());
}
RawData raw;
const bool hasTransparency = MaskMatch(mFlags, TRANSPARENCY);
- uint32_t numBuffers = mTextureStages.size() + (hasTransparency ? !CheckTextures(ALBEDO) + !CheckTextures(METALLIC | ROUGHNESS) + !CheckTextures(NORMAL) : !CheckTextures(ALBEDO | METALLIC) + !CheckTextures(NORMAL | ROUGHNESS));
+ // Why we add additional count here?
+ uint32_t numBuffers = mTextureStages.size() + (hasTransparency ? !CheckTextures(ALBEDO) + !CheckTextures(METALLIC | ROUGHNESS) + !CheckTextures(NORMAL)
+ : !CheckTextures(ALBEDO | METALLIC) + !CheckTextures(NORMAL | ROUGHNESS));
if(numBuffers == 0)
{
return raw;
}
}
- // Extra textures. TODO: emissive, occlusion etc.
+ // Extra textures.
if(checkStage(SUBSURFACE))
{
raw.mTextures.push_back({SyncImageLoader::Load(imagesPath + iTexture->mTexture.mImageUri), iTexture->mTexture.mSamplerFlags});
++iTexture;
}
+ if(checkStage(EMISSIVE))
+ {
+ raw.mTextures.push_back({SyncImageLoader::Load(imagesPath + iTexture->mTexture.mImageUri), iTexture->mTexture.mSamplerFlags});
+ ++iTexture;
+ }
+
return raw;
}
public: // DATA
uint32_t mFlags = 0x0;
- Index mEnvironmentIdx = 0;
- Vector4 mColor = Color::WHITE;
- float mMetallic = 1.f;
- float mRoughness = 1.f;
+ Index mEnvironmentIdx = 0;
+ Vector4 mColor = Color::WHITE;
+ Vector3 mEmissiveFactor = Vector3::ZERO;
+ float mMetallic = 1.f;
+ float mRoughness = 1.f;
+ float mOcclusionStrength = 1.f;
std::vector<TextureStage> mTextureStages;
};
auto& matDef = resources.mMaterials[mMaterialIdx].first;
actor.RegisterProperty("uMetallicFactor", matDef.mMetallic);
actor.RegisterProperty("uRoughnessFactor", matDef.mRoughness);
+ if(matDef.mFlags & MaterialDefinition::OCCLUSION)
+ {
+ actor.RegisterProperty("uOcclusionStrength", matDef.mOcclusionStrength);
+ }
+ if(matDef.mFlags & MaterialDefinition::EMISSIVE)
+ {
+ actor.RegisterProperty("uEmissiveFactor", matDef.mEmissiveFactor);
+ }
Index envIdx = matDef.mEnvironmentIdx;
actor.RegisterProperty("uIblIntensity", resources.mEnvironmentMaps[envIdx].first.mIblIntensity);
}
};
-const std::string PBR_SHADER_NAME = "dli_pbr";
-
void RetrieveBlendShapeComponents(const std::vector<MeshDefinition::BlendShape>& blendShapes, bool& hasPositions, bool& hasNormals, bool& hasTangents)
{
for(const auto& blendShape : blendShapes)
{
Hash hash;
- // note: could be per vertex / fragment component - in WatchViewer, these have the same name.
- hash.Add(PBR_SHADER_NAME);
-
const bool hasTransparency = MaskMatch(materialDef.mFlags, MaterialDefinition::TRANSPARENCY);
hash.Add(hasTransparency);
hash.Add("OCCL" /*USION*/);
}
+ if(MaskMatch(materialDef.mFlags, MaterialDefinition::EMISSIVE))
+ {
+ hash.Add("EMIS" /*SIVE*/);
+ }
+
if(MaskMatch(materialDef.mFlags, MaterialDefinition::GLTF_CHANNELS))
{
hash.Add("GLTF" /*_CHANNELS*/);
}
ShaderDefinition shaderDef;
- shaderDef.mVertexShaderPath = PBR_SHADER_NAME + ".vsh";
- shaderDef.mFragmentShaderPath = PBR_SHADER_NAME + ".fsh";
+ shaderDef.mUseBuiltInShader = true;
shaderDef.mRendererState = RendererState::DEPTH_TEST | RendererState::DEPTH_WRITE | RendererState::CULL_BACK;
auto& materialDef = *receiver.mMaterialDef;
shaderDef.mDefines.push_back("SSS");
}
- if(MaskMatch(receiver.mMaterialDef->mFlags, MaterialDefinition::OCCLUSION))
+ if(MaskMatch(materialDef.mFlags, MaterialDefinition::OCCLUSION))
{
shaderDef.mDefines.push_back("OCCLUSION");
}
- if(MaskMatch(receiver.mMaterialDef->mFlags, MaterialDefinition::GLTF_CHANNELS))
+ if(MaskMatch(materialDef.mFlags, MaterialDefinition::EMISSIVE))
+ {
+ shaderDef.mDefines.push_back("EMISSIVE");
+ }
+
+ if(MaskMatch(materialDef.mFlags, MaterialDefinition::GLTF_CHANNELS))
{
shaderDef.mDefines.push_back("GLTF_CHANNELS");
}
// INTERNAL INCLUDES
#include "dali-scene-loader/public-api/shader-definition.h"
#include "dali-scene-loader/public-api/utils.h"
+#include <dali-scene-loader/internal/graphics/builtin-shader-extern-gen.h>
namespace Dali
{
mFragmentShaderPath(other.mFragmentShaderPath),
mDefines(other.mDefines),
mHints(other.mHints),
- mUniforms(other.mUniforms)
+ mUniforms(other.mUniforms),
+ mUseBuiltInShader(false)
{
}
{
RawData raw;
- bool fail = false;
- raw.mVertexShaderSource = LoadTextFile((shadersPath + mVertexShaderPath).c_str(), &fail);
- if(!fail)
+ bool fail = false;
+ if(!mUseBuiltInShader)
{
- raw.mFragmentShaderSource = LoadTextFile((shadersPath + mFragmentShaderPath).c_str(), &fail);
+ raw.mVertexShaderSource = LoadTextFile((shadersPath + mVertexShaderPath).c_str(), &fail);
if(!fail)
{
- for(auto definevar : mDefines)
+ raw.mFragmentShaderSource = LoadTextFile((shadersPath + mFragmentShaderPath).c_str(), &fail);
+ if(fail)
{
- ApplyDefine(raw.mVertexShaderSource, definevar);
- ApplyDefine(raw.mFragmentShaderSource, definevar);
+ ExceptionFlinger(ASSERT_LOCATION) << "Failed to load shader source from '" << shadersPath + mFragmentShaderPath << "'.";
}
}
else
{
- ExceptionFlinger(ASSERT_LOCATION) << "Failed to load shader source from '" << shadersPath + mFragmentShaderPath << "'.";
+ ExceptionFlinger(ASSERT_LOCATION) << "Failed to load shader source from '" << shadersPath + mVertexShaderPath << "'.";
}
}
else
{
- ExceptionFlinger(ASSERT_LOCATION) << "Failed to load shader source from '" << shadersPath + mVertexShaderPath << "'.";
+ raw.mVertexShaderSource = SHADER_DEFAULT_PHYSICALLY_BASED_SHADER_VERT.data();
+ raw.mFragmentShaderSource = SHADER_DEFAULT_PHYSICALLY_BASED_SHADER_FRAG.data();
+ }
+
+ if(!fail)
+ {
+ for(auto definevar : mDefines)
+ {
+ ApplyDefine(raw.mVertexShaderSource, definevar);
+ ApplyDefine(raw.mFragmentShaderSource, definevar);
+ }
}
+
return raw;
}
std::string mFragmentShaderPath;
std::vector<std::string> mDefines;
std::vector<std::string> mHints;
-
- Property::Map mUniforms;
+ Property::Map mUniforms;
+ bool mUseBuiltInShader{false};
};
} // namespace SceneLoader
// Scene doesn't use both of point and directional light\r
NONE = 0,\r
// Scene use point light\r
- POINT_LIGHT,\r
+ POINT_LIGHT = 1,\r
// Scene use directional light\r
- DIRECTIONAL_LIGHT,\r
- // Scene use Image Based Lighting\r
- IMAGE_BASED_LIGHT,\r
- // Scene use Image Based Lighting and point light\r
- IMAGE_BASED_LIGHT_AND_POINT_LIGHT,\r
- // Scene use Image Based Lighting and directional light\r
- IMAGE_BASED_LIGHT_AND_DIRECTIONAL_LIGHT\r
+ DIRECTIONAL_LIGHT = 2\r
};\r
\r
/**\r
return GetImpl(keyboardFocusManager).MoveFocus(direction, deviceName);
}
+void SetFocusFinderRootActor(KeyboardFocusManager keyboardFocusManager, Actor actor)
+{
+ GetImpl(keyboardFocusManager).SetFocusFinderRootActor(actor);
+}
+
+void ResetFocusFinderRootActor(KeyboardFocusManager keyboardFocusManager)
+{
+ GetImpl(keyboardFocusManager).ResetFocusFinderRootActor();
+}
+
} // namespace DevelKeyboardFocusManager
} // namespace Toolkit
*/
DALI_TOOLKIT_API bool MoveFocus(KeyboardFocusManager keyboardFocusManager, Control::KeyboardFocus::Direction direction, const std::string& deviceName);
+/**
+ * @brief Sets the root actor to start moving focus when DefaultAlgorithm is enabled.
+ *
+ * @param[in] keyboardFocusManager The instance of KeyboardFocusManager
+ * @param[in] actor The root actor
+ */
+DALI_TOOLKIT_API void SetFocusFinderRootActor(KeyboardFocusManager keyboardFocusManager, Actor actor);
+
+/**
+ * @brief Resets the root actor that starts moving focus when DefaultAlgorithm is enabled.
+ * When reset, the window becomes root.
+ *
+ * @param[in] keyboardFocusManager The instance of KeyboardFocusManager
+ */
+DALI_TOOLKIT_API void ResetFocusFinderRootActor(KeyboardFocusManager keyboardFocusManager);
} // namespace DevelKeyboardFocusManager
/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include <limits>
// INTERNAL INCLUDES
-#include <dali-toolkit/devel-api/visuals/visual-actions-devel.h>
#include <dali-toolkit/devel-api/asset-manager/asset-manager.h>
#include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
#include <dali-toolkit/devel-api/controls/control-devel.h>
#include <dali-toolkit/devel-api/controls/control-wrapper-impl.h>
+#include <dali-toolkit/devel-api/visuals/visual-actions-devel.h>
#include <dali-toolkit/internal/styling/style-manager-impl.h>
#include <dali-toolkit/internal/visuals/visual-base-impl.h>
#include <dali-toolkit/internal/visuals/visual-string-constants.h>
Dali::Accessibility::Accessible* ExternalAccessibleGetter(Dali::Actor actor)
{
auto control = Toolkit::Control::DownCast(actor);
- if (!control)
+ if(!control)
{
return nullptr;
}
auto accessible = GetAccessibleObject();
auto lastPosition = accessible->GetLastPosition();
auto accessibleRect = accessible->GetExtents(Dali::Accessibility::CoordinateType::WINDOW);
- auto rect = GetShowingGeometry(accessibleRect, accessible);
+ auto rect = GetShowingGeometry(accessibleRect, accessible);
switch(mAccessibilityLastScreenRelativeMoveType)
{
mAccessibilityLastScreenRelativeMoveType = Dali::Accessibility::ScreenRelativeMoveType::OUTSIDE;
// recalculate mAccessibilityLastScreenRelativeMoveType accordingly to the initial position
CheckHighlightedObjectGeometry();
- mAccessibilityPositionNotification = mControlImpl.Self().AddPropertyNotification(Actor::Property::WORLD_POSITION, StepCondition(1.0f, 1.0f));
+ mAccessibilityPositionNotification = mControlImpl.Self().AddPropertyNotification(Actor::Property::WORLD_POSITION, StepCondition(1.0f, 1.0f));
mAccessibilityPositionNotification.SetNotifyMode(PropertyNotification::NOTIFY_ON_CHANGED);
- mAccessibilityPositionNotification.NotifySignal().Connect(this, [this](PropertyNotification&){ CheckHighlightedObjectGeometry(); });
+ mAccessibilityPositionNotification.NotifySignal().Connect(this, [this](PropertyNotification&) { CheckHighlightedObjectGeometry(); });
mIsAccessibilityPositionPropertyNotificationSet = true;
}
}
}
+void Control::Impl::RelayoutRequest(Visual::Base& object)
+{
+ mControlImpl.RelayoutRequest();
+}
+
bool Control::Impl::IsResourceReady() const
{
// Iterate through and check all the enabled visuals are ready
auto* accessible = controlImpl.GetAccessibleObject();
auto* parent = dynamic_cast<Dali::Accessibility::ActorAccessible*>(accessible->GetParent());
- if (parent)
+ if(parent)
{
parent->OnChildrenChanged();
}
void Control::Impl::CreateTransitions(std::vector<std::pair<Dali::Property::Index, Dali::Property::Map>>& sourceProperties,
std::vector<std::pair<Dali::Property::Index, Dali::Property::Map>>& destinationProperties,
- Dali::Toolkit::Control source, Dali::Toolkit::Control destination)
+ Dali::Toolkit::Control source,
+ Dali::Toolkit::Control destination)
{
// Retrieves background properties to be transitioned.
Dali::Property::Map backgroundSourcePropertyMap, backgroundDestinationPropertyMap;
#define DALI_TOOLKIT_CONTROL_DATA_IMPL_H
/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
void NotifyVisualEvent(Visual::Base& object, Property::Index signalId) override;
/**
+ * @brief Called when the visual needs relayout request.
+ * @param[in] object The visual who requests relayout
+ */
+ void RelayoutRequest(Visual::Base& object) override;
+
+ /**
* @copydoc Dali::Toolkit::DevelControl::RegisterVisual()
*/
void RegisterVisual(Property::Index index, Toolkit::Visual::Base& visual);
*/
void CreateTransitions(std::vector<std::pair<Dali::Property::Index, Dali::Property::Map>>& sourceProperties,
std::vector<std::pair<Dali::Property::Index, Dali::Property::Map>>& destinationProperties,
- Dali::Toolkit::Control source, Dali::Toolkit::Control destination);
+ Dali::Toolkit::Control source,
+ Dali::Toolkit::Control destination);
/**
* @brief Update visual properties.
std::string mSubStateName;
Property::Map mAccessibilityAttributes;
- int mLeftFocusableActorId; ///< Actor ID of Left focusable control.
- int mRightFocusableActorId; ///< Actor ID of Right focusable control.
- int mUpFocusableActorId; ///< Actor ID of Up focusable control.
- int mDownFocusableActorId; ///< Actor ID of Down focusable control.
- int mClockwiseFocusableActorId; ///< Actor ID of Clockwise focusable control.
- int mCounterClockwiseFocusableActorId; ///< Actor ID of Counter clockwise focusable control.
+ int mLeftFocusableActorId; ///< Actor ID of Left focusable control.
+ int mRightFocusableActorId; ///< Actor ID of Right focusable control.
+ int mUpFocusableActorId; ///< Actor ID of Up focusable control.
+ int mDownFocusableActorId; ///< Actor ID of Down focusable control.
+ int mClockwiseFocusableActorId; ///< Actor ID of Clockwise focusable control.
+ int mCounterClockwiseFocusableActorId; ///< Actor ID of Counter clockwise focusable control.
RegisteredVisualContainer mVisuals; ///< Stores visuals needed by the control, non trivial type so std::vector used.
std::string mStyleName;
VERTEX_SHADER += SHADER_GLTF_PHYSICALLY_BASED_SHADER_VERT.data();
FRAGMENT_SHADER = SHADER_GLTF_GLES_VERSION_300_DEF.data();
- bool useIBL = (scene3dView.GetLightType() >= Toolkit::Scene3dView::LightType::IMAGE_BASED_LIGHT);
+ bool useIBL = scene3dView.HasImageBasedLighting();
if(isMaterial)
{
MaterialInfo materialInfo = mMaterialArray[meshInfo.materialsIdx];
actor.RotateBy(orientation);
actor.SetProperty(Actor::Property::POSITION, translation);
- shader.RegisterProperty("uLightType", (scene3dView.GetLightType() & ~Toolkit::Scene3dView::LightType::IMAGE_BASED_LIGHT));
+ float hasLightSource = static_cast<float>(!!(scene3dView.GetLightType() & (Toolkit::Scene3dView::LightType::POINT_LIGHT | Toolkit::Scene3dView::LightType::DIRECTIONAL_LIGHT)));
+ float isPointLight = static_cast<float>(!!(scene3dView.GetLightType() & Toolkit::Scene3dView::LightType::POINT_LIGHT));
+ shader.RegisterProperty("uHasLightSource", hasLightSource);
+ shader.RegisterProperty("uIsPointLight", isPointLight);
shader.RegisterProperty("uLightVector", scene3dView.GetLightVector());
shader.RegisterProperty("uLightColor", scene3dView.GetLightColor());
- actor.RegisterProperty("uIsColor", meshInfo.attribute.COLOR.size() > 0);
+ actor.RegisterProperty("uHasVertexColor", meshInfo.attribute.COLOR.size() > 0 ? 1.0f : 0.0f);
if(isMaterial)
{
MaterialInfo materialInfo = mMaterialArray[meshInfo.materialsIdx];
if(materialInfo.alphaMode == "OPAQUE")
{
- actor.RegisterProperty("alphaMode", 0);
+ actor.RegisterProperty("uAlphaMode", 0.0f);
}
else if(materialInfo.alphaMode == "MASK")
{
- actor.RegisterProperty("alphaMode", 1);
+ actor.RegisterProperty("uAlphaMode", 1.0f);
}
else
{
- actor.RegisterProperty("alphaMode", 2);
+ actor.RegisterProperty("uAlphaMode", 2.0f);
}
actor.RegisterProperty("alphaCutoff", materialInfo.alphaCutoff);
mAnimationArray(),
mLightType(Toolkit::Scene3dView::LightType::NONE),
mLightVector(Vector3::ONE),
- mLightColor(Vector3::ONE)
+ mLightColor(Vector3::ONE),
+ mUseIBL(false)
{
}
bool Scene3dView::SetLight(Toolkit::Scene3dView::LightType type, Vector3 lightVector, Vector3 lightColor)
{
- if(type > Toolkit::Scene3dView::LightType::DIRECTIONAL_LIGHT)
- {
- return false;
- }
-
- mLightType = static_cast<Toolkit::Scene3dView::LightType>(
- (mLightType >= Toolkit::Scene3dView::LightType::IMAGE_BASED_LIGHT) ? Toolkit::Scene3dView::LightType::IMAGE_BASED_LIGHT + type : type);
-
+ mLightType = type;
mLightVector = lightVector;
mLightColor = lightColor;
for(auto&& shader : mShaderArray)
{
- shader.RegisterProperty("uLightType", (GetLightType() & ~Toolkit::Scene3dView::LightType::IMAGE_BASED_LIGHT));
+ float hasLightSource = static_cast<float>(!!(GetLightType() & (Toolkit::Scene3dView::LightType::POINT_LIGHT | Toolkit::Scene3dView::LightType::DIRECTIONAL_LIGHT)));
+ float isPointLight = static_cast<float>(!!(GetLightType() & Toolkit::Scene3dView::LightType::POINT_LIGHT));
+ shader.RegisterProperty("uHasLightSource", hasLightSource);
+ shader.RegisterProperty("uIsPointLight", isPointLight);
shader.RegisterProperty("uLightVector", lightVector);
shader.RegisterProperty("uLightColor", lightColor);
}
void Scene3dView::SetCubeMap(const std::string& diffuseTexturePath, const std::string& specularTexturePath, Vector4 scaleFactor)
{
- mLightType = Toolkit::Scene3dView::LightType::IMAGE_BASED_LIGHT;
-
// BRDF texture
const std::string imageDirPath = AssetManager::GetDaliImagePath();
const std::string imageBrdfUrl = imageDirPath + IMAGE_BRDF_FILE_NAME;
mSpecularTexture.GenerateMipmaps();
mIBLScaleFactor = scaleFactor;
+ mUseIBL = true;
}
bool Scene3dView::SetDefaultCamera(const Dali::Camera::Type type, const float nearPlane, const Vector3 cameraPosition)
return mSpecularTexture;
}
+bool Scene3dView::HasImageBasedLighting()
+{
+ return mUseIBL;
+}
+
Texture Scene3dView::GetDiffuseTexture()
{
return mDiffuseTexture;
*/\r
Texture GetSpecularTexture();\r
\r
+ /**\r
+ * @brief Get whether the scene has image based rendering or not.\r
+ */\r
+ bool HasImageBasedLighting();\r
+\r
private:\r
/**\r
* @brief Get Cropped image buffer.\r
Texture mBRDFTexture; // BRDF texture for the PBR rendering\r
Texture mSpecularTexture; // Specular cube map texture\r
Texture mDiffuseTexture; // Diffuse cube map texture\r
+ bool mUseIBL;\r
\r
private:\r
// Undefined copy constructor.\r
}
}
+Dali::Vector2 GetPosition(Dali::Actor actor)
+{
+ Vector2 screenPosition = actor.GetProperty<Vector2>(Actor::Property::SCREEN_POSITION);
+ Vector3 size = actor.GetCurrentProperty<Vector3>(Actor::Property::SIZE) * actor.GetCurrentProperty<Vector3>(Actor::Property::WORLD_SCALE);
+ bool positionUsesAnchorPoint = actor.GetProperty<bool>(Actor::Property::POSITION_USES_ANCHOR_POINT);
+ Vector3 anchorPointOffSet = size * (positionUsesAnchorPoint ? actor.GetCurrentProperty<Vector3>(Actor::Property::ANCHOR_POINT) : AnchorPoint::TOP_LEFT);
+ Vector2 position = Vector2(screenPosition.x - anchorPointOffSet.x, screenPosition.y - anchorPointOffSet.y);
+
+ return position;
+}
+
} // unnamed namespace
namespace Dali
return false;
}
- // child can be one of descendants
- // find direct child of ScrollView to avoid the ASSERT in ScrollTo
- auto parent = child.GetParent();
- while (parent && parent != Self())
- {
- child = parent;
- parent = child.GetParent();
- }
- if (!parent)
- {
- return false;
- }
+ auto childPosition = GetPosition(child);
+ auto selfPosition = GetPosition(Self());
+
+ scrollView.ScrollTo(childPosition - selfPosition, scrollView.GetScrollFlickDuration());
- // FIXME: ScrollTo does not work (snaps back to original position)
- scrollView.ScrollTo(child, scrollView.GetScrollFlickDuration());
return true;
}
mFocusedActorEnterKeySignal(),
mCurrentFocusActor(),
mFocusIndicatorActor(),
+ mFocusFinderRootActor(),
mFocusHistory(),
mSlotDelegate(this),
mCustomAlgorithmInterface(NULL),
}
else if (mEnableDefaultAlgorithm)
{
- Layer rootLayer;
- if (currentFocusActor)
+ Actor rootActor = mFocusFinderRootActor.GetHandle();
+ if(!rootActor)
{
- // Find the window of the focused actor.
- Integration::SceneHolder window = Integration::SceneHolder::Get(currentFocusActor);
- if (window)
+ if (currentFocusActor)
{
- rootLayer = window.GetRootLayer();
+ // Find the window of the focused actor.
+ Integration::SceneHolder window = Integration::SceneHolder::Get(currentFocusActor);
+ if (window)
+ {
+ rootActor = window.GetRootLayer();
+ }
+ }
+ else
+ {
+ // Searches from the currently focused window.
+ rootActor = mCurrentFocusedWindow.GetHandle();
}
}
- else
- {
- // Searches from the currently focused window.
- rootLayer = mCurrentFocusedWindow.GetHandle();
- }
- if (rootLayer)
+ if(rootActor)
{
// We should find it among the actors nearby.
- nextFocusableActor = Toolkit::FocusFinder::GetNearestFocusableActor(rootLayer, currentFocusActor, direction);
+ nextFocusableActor = Toolkit::FocusFinder::GetNearestFocusableActor(rootActor, currentFocusActor, direction);
}
}
}
return mEnableDefaultAlgorithm;
}
+void KeyboardFocusManager::SetFocusFinderRootActor(Actor actor)
+{
+ mFocusFinderRootActor = actor;
+}
+
+void KeyboardFocusManager::ResetFocusFinderRootActor()
+{
+ mFocusFinderRootActor.Reset();
+}
+
} // namespace Internal
} // namespace Toolkit
*/
bool IsDefaultAlgorithmEnabled() const;
+ /**
+ * @copydoc Toolkit::DevelKeyboardFocusManager::SetFocusFinderRootActor
+ */
+ void SetFocusFinderRootActor(Actor actor);
+
+ /**
+ * @copydoc Toolkit::DevelKeyboardFocusManager::ResetFocusFinderRootActor
+ */
+ void ResetFocusFinderRootActor();
+
public:
/**
* @copydoc Toolkit::KeyboardFocusManager::PreFocusChangeSignal()
Actor mFocusIndicatorActor; ///< The focus indicator actor shared by all the keyboard focusable actors for highlight
+ WeakHandle<Actor> mFocusFinderRootActor; ///<The root actor from which the focus finder is started.
+
FocusStack mFocusHistory; ///< Stack to contain pre-focused actor's BaseObject*
SlotDelegate<KeyboardFocusManager> mSlotDelegate;
bool mClearFocusOnTouch : 1; ///< Whether clear focus on touch.
bool mEnableDefaultAlgorithm : 1; ///< Whether use default algorithm focus
+
};
} // namespace Internal
uniform lowp vec3 uLightColor;
uniform lowp vec4 uBaseColorFactor;
uniform lowp vec2 uMetallicRoughnessFactors;
-uniform lowp int alphaMode;
uniform lowp float alphaCutoff;
+uniform lowp float uAlphaMode;
+uniform lowp float uHasLightSource;
in lowp vec2 vUV[2];
in lowp mat3 vTBN;
in lowp vec4 vColor;
-flat in int visLight;
in highp vec3 vLightDirection;
in highp vec3 vPositionToCamera;
vec3 getNormal()
{
#ifdef TEXTURE_NORMAL
- lowp vec3 n = texture( uNormalSampler, vUV[uNormalTexCoordIndex] ).rgb;
- n = normalize( vTBN * ( ( 2.0 * n - 1.0 ) * vec3( uNormalScale, uNormalScale, 1.0 ) ) );
+ lowp vec3 n = texture(uNormalSampler, vUV[uNormalTexCoordIndex]).rgb;
+ n = normalize(vTBN * ((2.0 * n - 1.0) * vec3(uNormalScale, uNormalScale, 1.0)));
#else
lowp vec3 n = normalize( vTBN[2].xyz );
#endif
return n;
}
-vec3 specularReflection( PBRInfo pbrInputs )
+vec3 specularReflection(PBRInfo pbrInputs)
{
- return pbrInputs.reflectance0 + ( pbrInputs.reflectance90 - pbrInputs.reflectance0 ) * pow( clamp( 1.0 - pbrInputs.VdotH, 0.0, 1.0 ), 5.0 );
+ return pbrInputs.reflectance0 + (pbrInputs.reflectance90 - pbrInputs.reflectance0) * pow(clamp(1.0 - pbrInputs.VdotH, 0.0, 1.0), 5.0);
}
-float geometricOcclusion( PBRInfo pbrInputs )
+float geometricOcclusion(PBRInfo pbrInputs)
{
mediump float NdotL = pbrInputs.NdotL;
mediump float NdotV = pbrInputs.NdotV;
return roughnessSq / (M_PI * f * f);
}
-vec3 linear( vec3 color )
+vec3 linear(vec3 color)
{
return pow(color,vec3(2.2));
}
lowp vec4 baseColor = vColor * uBaseColorFactor;
#endif
- if( alphaMode == 0 )
+ if(uAlphaMode < 0.5f)
{
baseColor.w = 1.0;
}
- else if( alphaMode == 1 )
+ else if(uAlphaMode < 1.5f)
{
- if( baseColor.w >= alphaCutoff )
+ if(baseColor.w >= alphaCutoff)
{
baseColor.w = 1.0;
}
// Calculate the shading terms for the microfacet specular shading model
lowp vec3 color = vec3(0.0);
- if( visLight == 1 )
+ if( uHasLightSource > 0.5f )
{
lowp vec3 F = specularReflection( pbrInputs );
lowp float G = geometricOcclusion( pbrInputs );
uniform mediump mat4 uModelMatrix;
uniform mediump mat4 uViewMatrix;
uniform mediump mat4 uProjection;
-uniform lowp int uLightType;
uniform mediump vec3 uLightVector;
-uniform lowp int uIsColor;
+uniform lowp float uIsPointLight;
+uniform lowp float uHasVertexColor;
out lowp vec2 vUV[2];
out lowp mat3 vTBN;
out lowp vec4 vColor;
-flat out int visLight;
out highp vec3 vLightDirection;
out highp vec3 vPositionToCamera;
void main()
{
highp vec4 invY = vec4(1.0, -1.0, 1.0, 1.0);
- highp vec4 positionW = uModelMatrix * vec4( aPosition * uSize, 1.0 );
- highp vec4 positionV = uViewMatrix * ( invY * positionW );
+ highp vec4 positionW = uModelMatrix * vec4(aPosition * uSize, 1.0);
+ highp vec4 positionV = uViewMatrix * (invY * positionW);
- vPositionToCamera = transpose( mat3( uViewMatrix ) ) * ( -vec3( positionV.xyz / positionV.w ) );
+ vPositionToCamera = transpose(mat3(uViewMatrix)) * (-vec3(positionV.xyz / positionV.w));
vPositionToCamera *= invY.xyz;
lowp vec3 bitangent = cross(aNormal, aTangent.xyz) * aTangent.w;
- vTBN = mat3( uModelMatrix ) * mat3(aTangent.xyz, bitangent, aNormal);
+ vTBN = mat3(uModelMatrix) * mat3(aTangent.xyz, bitangent, aNormal);
vUV[0] = aTexCoord0;
vUV[1] = aTexCoord1;
- visLight = 1;
- if( uLightType == 1 )
- {
- vLightDirection = ( invY.xyz * uLightVector ) - ( positionW.xyz / positionW.w );
- }
- else if( uLightType == 2 )
- {
- vLightDirection = -( invY.xyz * uLightVector );
- }
- else
- {
- visLight = 0;
- }
-
- vColor = vec4( 1.0 );
- if( uIsColor == 1 )
- {
- vColor = aVertexColor;
- }
+ vLightDirection = mix(-(invY.xyz * uLightVector), (invY.xyz * uLightVector) - (positionW.xyz / positionW.w), uIsPointLight);
+
+ vColor = mix(vec4(1.0f), aVertexColor, uHasVertexColor);
gl_Position = uProjection * positionV; // needs w for proper perspective correction
gl_Position = gl_Position/gl_Position.w;
if(visualFactory)
{
auto& textureManager = GetImplementation(visualFactory).GetTextureManager();
- mUrl = textureManager.AddExternalEncodedImageBuffer(encodedImageBuffer);
+ mUrl = textureManager.AddEncodedImageBuffer(encodedImageBuffer);
}
}
}
else if(VisualUrl::BUFFER == VisualUrl::GetProtocolType(mUrl))
{
- textureManager.RemoveExternalEncodedImageBuffer(mUrl);
+ textureManager.RemoveEncodedImageBuffer(mUrl);
}
}
}
"Unknown"
// clang-format on
#endif
-namespace
+
+// Due to the compile issue, this specialized template code must be defined top of this code.
+template<>
+void TextureCacheManager::RemoveTextureInfoByIndex<TextureCacheManager::EncodedImageBufferInfoContainerType>(TextureCacheManager::EncodedImageBufferInfoContainerType& cacheContainer, const TextureCacheManager::TextureCacheIndex& removeContainerIndex)
{
-} // Anonymous namespace
+ // Swap last data of cacheContainer.
+ if(static_cast<std::size_t>(removeContainerIndex.GetIndex() + 1) < cacheContainer.size())
+ {
+ // First, change the cache index infomations inside of converter
+ mTextureIdConverter[cacheContainer.back().bufferId] = static_cast<std::uint32_t>(removeContainerIndex);
+
+ // After change converter, swap the value between current data and last data.
+ std::swap(cacheContainer[removeContainerIndex.GetIndex()], cacheContainer.back());
+ }
+
+ // Now we can assume that latest data should be removed. pop_back.
+ cacheContainer.pop_back();
+}
+
+template<class ContainerType>
+void TextureCacheManager::RemoveTextureInfoByIndex(ContainerType& cacheContainer, const TextureCacheManager::TextureCacheIndex& removeContainerIndex)
+{
+ // Swap last data of cacheContainer.
+ if(static_cast<std::size_t>(removeContainerIndex.GetIndex() + 1) < cacheContainer.size())
+ {
+ // First, change the cache index infomations inside of converter
+ mTextureIdConverter[cacheContainer.back().textureId] = static_cast<std::uint32_t>(removeContainerIndex);
+
+ // After change converter, swap the value between current data and last data.
+ std::swap(cacheContainer[removeContainerIndex.GetIndex()], cacheContainer.back());
+ }
+
+ // Now we can assume that latest data should be removed. pop_back.
+ cacheContainer.pop_back();
+}
TextureCacheManager::TextureCacheManager()
-: mCurrentTextureId(0)
{
}
VisualUrl TextureCacheManager::GetVisualUrl(const TextureCacheManager::TextureId& textureId)
{
VisualUrl visualUrl("");
- TextureCacheIndex cacheIndex = GetCacheIndexFromId(textureId);
+ TextureCacheIndex cacheIndex = static_cast<TextureCacheIndex>(mTextureIdConverter[static_cast<std::uint32_t>(textureId)]);
- if(cacheIndex != INVALID_CACHE_INDEX)
+ switch(static_cast<TextureCacheIndexType>(cacheIndex.detailValue.type))
{
- DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureCacheManager::GetVisualUrl. Using cached texture id=%d, textureId=%d\n", cacheIndex, textureId);
+ case TextureCacheIndexType::TEXTURE_CACHE_INDEX_TYPE_LOCAL:
+ {
+ DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureCacheManager::GetVisualUrl. Using cached texture index=%d, textureId=%d\n", cacheIndex.GetIndex(), textureId);
- TextureInfo& cachedTextureInfo(mTextureInfoContainer[cacheIndex]);
- visualUrl = cachedTextureInfo.url;
+ TextureInfo& cachedTextureInfo(mTextureInfoContainer[cacheIndex.GetIndex()]);
+ visualUrl = cachedTextureInfo.url;
+ break;
+ }
+ case TextureCacheIndexType::TEXTURE_CACHE_INDEX_TYPE_TEXTURE:
+ {
+ DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureCacheManager::GetVisualUrl. Using cached external texture index=%d, textureId=%d\n", cacheIndex.GetIndex(), textureId);
+ visualUrl = VisualUrl::CreateTextureUrl(std::to_string(textureId));
+ break;
+ }
+ case TextureCacheIndexType::TEXTURE_CACHE_INDEX_TYPE_BUFFER:
+ {
+ DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureCacheManager::GetVisualUrl. Using cached buffer index=%d, bufferId=%d\n", cacheIndex.GetIndex(), textureId);
+ visualUrl = VisualUrl::CreateBufferUrl(std::to_string(textureId));
+ break;
+ }
+ default:
+ {
+ break;
+ }
}
+
return visualUrl;
}
TextureCacheManager::LoadState TextureCacheManager::GetTextureState(const TextureCacheManager::TextureId& textureId)
{
- LoadState loadState = TextureCacheManager::LoadState::NOT_STARTED;
+ LoadState loadState = TextureCacheManager::LoadState::NOT_STARTED;
+ TextureCacheIndex cacheIndex = static_cast<TextureCacheIndex>(mTextureIdConverter[static_cast<std::uint32_t>(textureId)]);
- TextureCacheIndex cacheIndex = GetCacheIndexFromId(textureId);
- if(cacheIndex != INVALID_CACHE_INDEX)
- {
- TextureInfo& cachedTextureInfo(mTextureInfoContainer[cacheIndex]);
- loadState = cachedTextureInfo.loadState;
- }
- else
+ switch(static_cast<TextureCacheIndexType>(cacheIndex.detailValue.type))
{
- for(auto&& elem : mExternalTextures)
+ case TextureCacheIndexType::TEXTURE_CACHE_INDEX_TYPE_LOCAL:
{
- if(elem.textureId == textureId)
- {
- loadState = LoadState::UPLOADED;
- break;
- }
+ TextureInfo& cachedTextureInfo(mTextureInfoContainer[cacheIndex.GetIndex()]);
+ loadState = cachedTextureInfo.loadState;
+ break;
+ }
+ case TextureCacheIndexType::TEXTURE_CACHE_INDEX_TYPE_TEXTURE:
+ {
+ loadState = LoadState::UPLOADED;
+ break;
+ }
+ default:
+ {
+ break;
}
}
+
return loadState;
}
TextureCacheManager::LoadState TextureCacheManager::GetTextureStateInternal(const TextureCacheManager::TextureId& textureId)
{
- LoadState loadState = TextureCacheManager::LoadState::NOT_STARTED;
-
+ LoadState loadState = TextureCacheManager::LoadState::NOT_STARTED;
TextureCacheIndex cacheIndex = GetCacheIndexFromId(textureId);
if(cacheIndex != INVALID_CACHE_INDEX)
{
- TextureInfo& cachedTextureInfo(mTextureInfoContainer[cacheIndex]);
+ TextureInfo& cachedTextureInfo(mTextureInfoContainer[cacheIndex.GetIndex()]);
loadState = cachedTextureInfo.loadState;
}
TextureSet TextureCacheManager::GetTextureSet(const TextureCacheManager::TextureId& textureId)
{
- TextureSet textureSet; // empty handle
+ TextureSet textureSet; // empty handle
+ TextureCacheIndex cacheIndex = static_cast<TextureCacheIndex>(mTextureIdConverter[static_cast<std::uint32_t>(textureId)]);
- TextureCacheIndex cacheIndex = GetCacheIndexFromId(textureId);
- if(cacheIndex != INVALID_CACHE_INDEX)
+ switch(static_cast<TextureCacheIndexType>(cacheIndex.detailValue.type))
{
- TextureInfo& cachedTextureInfo(mTextureInfoContainer[cacheIndex]);
- textureSet = cachedTextureInfo.textureSet;
- }
- else
- {
- for(auto&& elem : mExternalTextures)
+ case TextureCacheIndexType::TEXTURE_CACHE_INDEX_TYPE_LOCAL:
{
- if(elem.textureId == textureId)
- {
- textureSet = elem.textureSet;
- break;
- }
+ TextureInfo& cachedTextureInfo(mTextureInfoContainer[cacheIndex.GetIndex()]);
+ textureSet = cachedTextureInfo.textureSet;
+ break;
+ }
+ case TextureCacheIndexType::TEXTURE_CACHE_INDEX_TYPE_TEXTURE:
+ {
+ textureSet = mExternalTextures[cacheIndex.GetIndex()].textureSet;
+ break;
+ }
+ default:
+ {
+ break;
}
}
+
return textureSet;
}
TextureSet TextureCacheManager::GetExternalTextureSet(const TextureCacheManager::TextureId& textureId)
{
- TextureSet textureSet; // empty handle
- for(auto&& elem : mExternalTextures)
+ TextureSet textureSet; // empty handle
+ TextureCacheIndex cacheIndex = GetCacheIndexFromExternalTextureId(textureId);
+ if(cacheIndex != INVALID_CACHE_INDEX)
{
- if(elem.textureId == textureId)
- {
- textureSet = elem.textureSet;
- break;
- }
+ textureSet = mExternalTextures[cacheIndex.GetIndex()].textureSet;
}
return textureSet;
}
-EncodedImageBuffer TextureCacheManager::GetEncodedImageBuffer(const TextureCacheManager::TextureId& textureId)
+EncodedImageBuffer TextureCacheManager::GetEncodedImageBuffer(const TextureCacheManager::TextureId& bufferId)
{
EncodedImageBuffer encodedImageBuffer; // empty handle
- for(auto&& elem : mEncodedBufferTextures)
+ TextureCacheIndex cacheIndex = GetCacheIndexFromEncodedImageBufferId(bufferId);
+ if(cacheIndex != INVALID_CACHE_INDEX)
{
- if(elem.textureId == textureId)
- {
- encodedImageBuffer = elem.encodedImageBuffer;
- break;
- }
+ encodedImageBuffer = mEncodedImageBuffers[cacheIndex.GetIndex()].encodedImageBuffer;
}
return encodedImageBuffer;
}
-EncodedImageBuffer TextureCacheManager::GetEncodedImageBuffer(const std::string& url)
+EncodedImageBuffer TextureCacheManager::GetEncodedImageBuffer(const VisualUrl& url)
{
EncodedImageBuffer encodedImageBuffer; // empty handle
- if(url.size() > 0 && VisualUrl::BUFFER == VisualUrl::GetProtocolType(url))
+ if(url.IsValid() && VisualUrl::BUFFER == url.GetProtocolType())
{
- std::string location = VisualUrl::GetLocation(url);
+ std::string location = url.GetLocation();
if(location.size() > 0u)
{
- TextureId targetId = std::stoi(location);
- return GetEncodedImageBuffer(targetId);
+ TextureId bufferId = std::stoi(location);
+ return GetEncodedImageBuffer(bufferId);
}
}
return encodedImageBuffer;
std::string TextureCacheManager::AddExternalTexture(const TextureSet& textureSet)
{
- TextureCacheManager::ExternalTextureInfo info(GenerateUniqueTextureId(), textureSet);
- mExternalTextures.emplace_back(info);
- return VisualUrl::CreateTextureUrl(std::to_string(info.textureId));
+ TextureId textureId = GenerateTextureId(TextureCacheIndex(TextureCacheIndexType::TEXTURE_CACHE_INDEX_TYPE_TEXTURE, mExternalTextures.size()));
+
+ TextureCacheManager::ExternalTextureInfo textureInfo(textureId, textureSet);
+ mExternalTextures.emplace_back(textureInfo);
+
+ DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureCacheManager::AddExternalTexture() : New texture registered. textureId:%d\n", textureInfo.textureId);
+
+ return VisualUrl::CreateTextureUrl(std::to_string(textureInfo.textureId));
}
-std::string TextureCacheManager::AddExternalEncodedImageBuffer(const EncodedImageBuffer& encodedImageBuffer)
+std::string TextureCacheManager::AddEncodedImageBuffer(const EncodedImageBuffer& encodedImageBuffer)
{
// Duplication check
- for(auto&& elem : mEncodedBufferTextures)
+ TextureHash bufferHash = static_cast<TextureHash>(encodedImageBuffer.GetHash());
+ TextureCacheIndex bufferCacheIndex = FindCachedEncodedImageBuffer(bufferHash, encodedImageBuffer);
+ if(bufferCacheIndex != INVALID_CACHE_INDEX)
{
- if(elem.encodedImageBuffer == encodedImageBuffer)
- {
- // If same buffer added, increase reference count and return.
- elem.referenceCount++;
- return VisualUrl::CreateBufferUrl(std::to_string(elem.textureId));
- }
+ EncodedImageBufferInfo& bufferInfo(mEncodedImageBuffers[bufferCacheIndex.GetIndex()]);
+
+ DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureCacheManager::AddExternalEncodedImageBuffer() : Increase reference. bufferId:%d, cache index:%d, reference:%d\n", bufferInfo.bufferId, bufferCacheIndex.GetIndex(), static_cast<int>(bufferInfo.referenceCount));
+
+ // If same buffer added, increase reference count and return.
+ bufferInfo.referenceCount++;
+ return VisualUrl::CreateBufferUrl(std::to_string(bufferInfo.bufferId));
}
- TextureCacheManager::EncodedBufferTextureInfo info(GenerateUniqueTextureId(), encodedImageBuffer);
- mEncodedBufferTextures.emplace_back(info);
- return VisualUrl::CreateBufferUrl(std::to_string(info.textureId));
+
+ TextureId bufferId = GenerateTextureId(TextureCacheIndex(TextureCacheIndexType::TEXTURE_CACHE_INDEX_TYPE_BUFFER, mEncodedImageBuffers.size()));
+
+ TextureCacheManager::EncodedImageBufferInfo info(bufferId, bufferHash, encodedImageBuffer);
+ mEncodedImageBuffers.emplace_back(info);
+
+ // Insert TextureHashContainer
+ // Find exist list -or- Create new list.
+ std::vector<TextureId>& idList = mTextureHashContainer[bufferHash];
+ // We already assume that list doesn't contain id. just emplace back
+ idList.emplace_back(bufferId);
+
+ DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureCacheManager::AddExternalEncodedImageBuffer() : New buffer regested. bufferId:%d\n", info.bufferId);
+
+ return VisualUrl::CreateBufferUrl(std::to_string(info.bufferId));
}
-TextureSet TextureCacheManager::RemoveExternalTexture(const std::string& url)
+TextureSet TextureCacheManager::RemoveExternalTexture(const VisualUrl& url)
{
- if(url.size() > 0u)
+ TextureSet textureSet;
+ bool removeTextureInfo = false;
+ TextureCacheIndex removeTextureIndex = INVALID_CACHE_INDEX;
+ if(url.IsValid())
{
- if(VisualUrl::TEXTURE == VisualUrl::GetProtocolType(url))
+ if(VisualUrl::TEXTURE == url.GetProtocolType())
{
// get the location from the Url
- std::string location = VisualUrl::GetLocation(url);
+ std::string location = url.GetLocation();
if(location.size() > 0u)
{
- TextureId id = std::stoi(location);
- const auto end = mExternalTextures.end();
- for(auto iter = mExternalTextures.begin(); iter != end; ++iter)
+ TextureId textureId = std::stoi(location);
+ removeTextureIndex = GetCacheIndexFromExternalTextureId(textureId);
+ if(removeTextureIndex != INVALID_CACHE_INDEX)
{
- if(iter->textureId == id)
+ ExternalTextureInfo& textureInfo(mExternalTextures[removeTextureIndex.GetIndex()]);
+ DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureCacheManager::RemoveExternalTexture(url:%s) textureId:%d reference:%d\n", url.GetUrl().c_str(), textureId, static_cast<int>(textureInfo.referenceCount));
+ textureSet = textureInfo.textureSet;
+ if(--(textureInfo.referenceCount) <= 0)
{
- auto textureSet = iter->textureSet;
- if(--(iter->referenceCount) <= 0)
- {
- mExternalTextures.erase(iter);
- }
- return textureSet;
+ removeTextureInfo = true;
+ // id life is finished. Remove it at converter
+ mTextureIdConverter.Remove(textureId);
}
}
}
}
}
- return TextureSet();
+
+ // Post removal process to avoid mExternalTextures reference problems.
+ if(removeTextureInfo)
+ {
+ // Swap last data of mExternalTextures, and pop_back.
+ RemoveTextureInfoByIndex(mExternalTextures, removeTextureIndex);
+ }
+ return textureSet;
}
-EncodedImageBuffer TextureCacheManager::RemoveExternalEncodedImageBuffer(const std::string& url)
+EncodedImageBuffer TextureCacheManager::RemoveEncodedImageBuffer(const VisualUrl& url)
{
- if(url.size() > 0u)
+ EncodedImageBuffer encodedImageBuffer;
+ bool removeBufferInfo = false;
+ TextureCacheIndex removeBufferIndex = INVALID_CACHE_INDEX;
+ if(url.IsValid())
{
- if(VisualUrl::BUFFER == VisualUrl::GetProtocolType(url))
+ if(VisualUrl::BUFFER == url.GetProtocolType())
{
// get the location from the Url
- std::string location = VisualUrl::GetLocation(url);
+ std::string location = url.GetLocation();
if(location.size() > 0u)
{
- TextureId id = std::stoi(location);
- const auto end = mEncodedBufferTextures.end();
- for(auto iter = mEncodedBufferTextures.begin(); iter != end; ++iter)
+ TextureId bufferId = std::stoi(location);
+ removeBufferIndex = GetCacheIndexFromEncodedImageBufferId(bufferId);
+
+ if(removeBufferIndex != INVALID_CACHE_INDEX)
{
- if(iter->textureId == id)
+ EncodedImageBufferInfo& bufferInfo(mEncodedImageBuffers[removeBufferIndex.GetIndex()]);
+ DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureCacheManager::RemoveEncodedImageBuffer(url:%s) bufferId:%d reference:%d\n", url.GetUrl().c_str(), bufferId, static_cast<int>(bufferInfo.referenceCount));
+
+ encodedImageBuffer = bufferInfo.encodedImageBuffer;
+ if(--(bufferInfo.referenceCount) <= 0)
{
- auto encodedImageBuffer = iter->encodedImageBuffer;
- if(--(iter->referenceCount) <= 0)
- {
- mEncodedBufferTextures.erase(iter);
- }
- return encodedImageBuffer;
+ removeBufferInfo = true;
+ // Step 1. remove current textureId information in mTextureHashContainer.
+ RemoveHashId(bufferInfo.bufferHash, bufferId);
+ // Step 2. id life is finished. Remove it at converter
+ mTextureIdConverter.Remove(bufferId);
}
}
}
}
}
- return EncodedImageBuffer();
+
+ // Post removal process to avoid mEncodedImageBuffers reference problems.
+ if(removeBufferInfo)
+ {
+ // Step 3. swap last data of mEncodedImageBuffers, and pop_back.
+ RemoveTextureInfoByIndex(mEncodedImageBuffers, removeBufferIndex);
+ }
+ return encodedImageBuffer;
}
void TextureCacheManager::UseExternalResource(const VisualUrl& url)
std::string location = url.GetLocation();
if(location.size() > 0u)
{
- TextureId id = std::stoi(location);
- for(auto&& elem : mExternalTextures)
+ TextureId id = std::stoi(location);
+ TextureCacheIndex cacheIndex = GetCacheIndexFromExternalTextureId(id);
+ if(cacheIndex != INVALID_CACHE_INDEX)
{
- if(elem.textureId == id)
- {
- elem.referenceCount++;
- return;
- }
+ ExternalTextureInfo& textureInfo(mExternalTextures[cacheIndex.GetIndex()]);
+ DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureCacheManager::UseExternalResource(url:%s) type:TEXTURE, location:%s, reference:%d\n", url.GetUrl().c_str(), url.GetLocation().c_str(), static_cast<int>(textureInfo.referenceCount));
+
+ textureInfo.referenceCount++;
+ return;
}
}
}
std::string location = url.GetLocation();
if(location.size() > 0u)
{
- TextureId id = std::stoi(location);
- for(auto&& elem : mEncodedBufferTextures)
+ TextureId id = std::stoi(location);
+ TextureCacheIndex cacheIndex = GetCacheIndexFromEncodedImageBufferId(id);
+ if(cacheIndex != INVALID_CACHE_INDEX)
{
- if(elem.textureId == id)
- {
- elem.referenceCount++;
- return;
- }
+ EncodedImageBufferInfo& bufferInfo(mEncodedImageBuffers[cacheIndex.GetIndex()]);
+ DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureCacheManager::UseExternalResource(url:%s) type:BUFFER, location:%s, reference:%d\n", url.GetUrl().c_str(), url.GetLocation().c_str(), static_cast<int>(bufferInfo.referenceCount));
+
+ bufferInfo.referenceCount++;
+ return;
}
}
}
}
-TextureCacheManager::TextureId TextureCacheManager::GenerateUniqueTextureId()
+TextureCacheManager::TextureId TextureCacheManager::GenerateTextureId(const TextureCacheIndex& textureCacheIndex)
{
- return mCurrentTextureId++;
+ return mTextureIdConverter.Add(static_cast<std::uint32_t>(textureCacheIndex.indexValue));
}
TextureCacheManager::TextureCacheIndex TextureCacheManager::GetCacheIndexFromId(const TextureCacheManager::TextureId& textureId)
{
- const TextureCacheIndex size = static_cast<TextureCacheIndex>(mTextureInfoContainer.size());
+ if(textureId == INVALID_TEXTURE_ID) return INVALID_CACHE_INDEX;
- for(TextureCacheIndex i = 0; i < size; ++i)
+ TextureCacheIndex cacheIndex = static_cast<TextureCacheIndex>(mTextureIdConverter[static_cast<std::uint32_t>(textureId)]);
+ if(DALI_UNLIKELY(cacheIndex.detailValue.type != TextureCacheIndexType::TEXTURE_CACHE_INDEX_TYPE_LOCAL))
{
- if(mTextureInfoContainer[i].textureId == textureId)
+ return INVALID_CACHE_INDEX;
+ }
+
+ DALI_ASSERT_DEBUG(static_cast<std::size_t>(cacheIndex.GetIndex()) < mTextureInfoContainer.size());
+
+ return cacheIndex;
+}
+
+TextureCacheManager::TextureCacheIndex TextureCacheManager::GetCacheIndexFromExternalTextureId(const TextureCacheManager::TextureId& textureId)
+{
+ if(textureId == INVALID_TEXTURE_ID) return INVALID_CACHE_INDEX;
+
+ TextureCacheIndex cacheIndex = static_cast<TextureCacheIndex>(mTextureIdConverter[static_cast<std::uint32_t>(textureId)]);
+ if(DALI_UNLIKELY(cacheIndex.detailValue.type != TextureCacheIndexType::TEXTURE_CACHE_INDEX_TYPE_TEXTURE))
+ {
+ return INVALID_CACHE_INDEX;
+ }
+
+ DALI_ASSERT_DEBUG(static_cast<std::size_t>(cacheIndex.GetIndex()) < mExternalTextures.size());
+
+ return cacheIndex;
+}
+
+TextureCacheManager::TextureCacheIndex TextureCacheManager::GetCacheIndexFromEncodedImageBufferId(const TextureCacheManager::TextureId& bufferId)
+{
+ if(bufferId == INVALID_TEXTURE_ID) return INVALID_CACHE_INDEX;
+
+ TextureCacheIndex cacheIndex = static_cast<TextureCacheIndex>(mTextureIdConverter[static_cast<std::uint32_t>(bufferId)]);
+ if(DALI_UNLIKELY(cacheIndex.detailValue.type != TextureCacheIndexType::TEXTURE_CACHE_INDEX_TYPE_BUFFER))
+ {
+ return INVALID_CACHE_INDEX;
+ }
+
+ DALI_ASSERT_DEBUG(static_cast<std::size_t>(cacheIndex.GetIndex()) < mEncodedImageBuffers.size());
+
+ return cacheIndex;
+}
+
+TextureCacheManager::TextureCacheIndex TextureCacheManager::FindCachedEncodedImageBuffer(const TextureCacheManager::TextureHash& hash, const EncodedImageBuffer& encodedImageBuffer)
+{
+ // Iterate through our hashes to find a match.
+ const auto& hashIterator = mTextureHashContainer.find(hash);
+ if(hashIterator != mTextureHashContainer.cend())
+ {
+ for(const auto& id : hashIterator->second)
{
- return i;
+ // We have a match, now we check all the original parameters in case of a hash collision.
+ TextureCacheIndex cacheIndex = GetCacheIndexFromEncodedImageBufferId(id);
+ if(cacheIndex != INVALID_CACHE_INDEX)
+ {
+ EncodedImageBufferInfo& bufferInfo(mEncodedImageBuffers[cacheIndex.GetIndex()]);
+
+ if(bufferInfo.encodedImageBuffer == encodedImageBuffer)
+ {
+ // The found encoded image buffer.
+ return cacheIndex;
+ }
+ }
}
}
+ // Default to an invalid ID, in case we do not find a match.
return INVALID_CACHE_INDEX;
}
TextureCacheManager::TextureHash TextureCacheManager::GenerateHash(
- const std::string& url,
+ const VisualUrl& url,
const Dali::ImageDimensions& size,
const Dali::FittingMode::Type& fittingMode,
const Dali::SamplingMode::Type& samplingMode,
const TextureCacheManager::UseAtlas& useAtlas,
- const TextureCacheManager::TextureId& maskTextureId)
+ const TextureCacheManager::TextureId& maskTextureId,
+ const bool& cropToMask)
{
- std::vector<std::uint8_t> hashTarget(url.begin(), url.end());
- const size_t urlLength = url.length();
+ std::vector<std::uint8_t> hashTarget(url.GetUrl().begin(), url.GetUrl().end());
+ const size_t urlLength = hashTarget.size();
const uint16_t width = size.GetWidth();
const uint16_t height = size.GetWidth();
if(maskTextureId != INVALID_TEXTURE_ID)
{
auto textureIdIndex = hashTarget.size();
- hashTarget.resize(hashTarget.size() + sizeof(TextureId));
+ hashTarget.resize(hashTarget.size() + sizeof(TextureId) + 1u);
std::uint8_t* hashTargetPtr = reinterpret_cast<std::uint8_t*>(&(hashTarget[textureIdIndex]));
// Append the texture id to the end of the URL byte by byte:
*hashTargetPtr++ = saltedMaskTextureId & 0xff;
saltedMaskTextureId >>= 8u;
}
+ *hashTargetPtr++ = (cropToMask ? 'C' : 'M');
}
return Dali::CalculateHash(hashTarget);
TextureCacheManager::TextureCacheIndex TextureCacheManager::FindCachedTexture(
const TextureCacheManager::TextureHash& hash,
- const std::string& url,
+ const VisualUrl& url,
const Dali::ImageDimensions& size,
const Dali::FittingMode::Type& fittingMode,
const Dali::SamplingMode::Type& samplingMode,
const TextureCacheManager::UseAtlas& useAtlas,
const TextureCacheManager::TextureId& maskTextureId,
+ const bool& cropToMask,
const TextureCacheManager::MultiplyOnLoad& preMultiplyOnLoad,
- bool isAnimatedImage)
+ const bool& isAnimatedImage)
{
- // Default to an invalid ID, in case we do not find a match.
- TextureCacheIndex cacheIndex = INVALID_CACHE_INDEX;
-
// Iterate through our hashes to find a match.
- const TextureCacheIndex count = static_cast<TextureCacheIndex>(mTextureInfoContainer.size());
- for(TextureCacheIndex i = 0u; i < count; ++i)
+ const auto& hashIterator = mTextureHashContainer.find(hash);
+ if(hashIterator != mTextureHashContainer.cend())
{
- if(mTextureInfoContainer[i].hash == hash)
+ for(const auto& textureId : hashIterator->second)
{
// We have a match, now we check all the original parameters in case of a hash collision.
- TextureInfo& textureInfo(mTextureInfoContainer[i]);
-
- if((url == textureInfo.url.GetUrl()) &&
- (useAtlas == textureInfo.useAtlas) &&
- (maskTextureId == textureInfo.maskTextureId) &&
- (size == textureInfo.desiredSize) &&
- (isAnimatedImage == textureInfo.isAnimatedImageFormat) &&
- ((size.GetWidth() == 0 && size.GetHeight() == 0) ||
- (fittingMode == textureInfo.fittingMode &&
- samplingMode == textureInfo.samplingMode)))
+ TextureCacheIndex cacheIndex = GetCacheIndexFromId(textureId);
+ if(cacheIndex != INVALID_CACHE_INDEX)
{
- // 1. If preMultiplyOnLoad is MULTIPLY_ON_LOAD, then textureInfo.preMultiplyOnLoad should be true. The premultiplication result can be different.
- // 2. If preMultiplyOnLoad is LOAD_WITHOUT_MULTIPLY, then textureInfo.preMultiplied should be false.
- if((preMultiplyOnLoad == MultiplyOnLoad::MULTIPLY_ON_LOAD && textureInfo.preMultiplyOnLoad) || (preMultiplyOnLoad == MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY && !textureInfo.preMultiplied))
+ TextureInfo& textureInfo(mTextureInfoContainer[cacheIndex.GetIndex()]);
+
+ if((url.GetUrl() == textureInfo.url.GetUrl()) &&
+ (useAtlas == textureInfo.useAtlas) &&
+ (maskTextureId == textureInfo.maskTextureId) &&
+ (cropToMask == textureInfo.cropToMask) &&
+ (size == textureInfo.desiredSize) &&
+ (isAnimatedImage == textureInfo.isAnimatedImageFormat) &&
+ ((size.GetWidth() == 0 && size.GetHeight() == 0) ||
+ (fittingMode == textureInfo.fittingMode &&
+ samplingMode == textureInfo.samplingMode)))
{
- // The found Texture is a match.
- cacheIndex = i;
- break;
+ // 1. If preMultiplyOnLoad is MULTIPLY_ON_LOAD, then textureInfo.preMultiplyOnLoad should be true. The premultiplication result can be different.
+ // 2. If preMultiplyOnLoad is LOAD_WITHOUT_MULTIPLY, then textureInfo.preMultiplied should be false.
+ if((preMultiplyOnLoad == MultiplyOnLoad::MULTIPLY_ON_LOAD && textureInfo.preMultiplyOnLoad) || (preMultiplyOnLoad == MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY && !textureInfo.preMultiplied))
+ {
+ // The found Texture is a match.
+ return cacheIndex;
+ }
}
}
}
}
- return cacheIndex;
+ // Default to an invalid ID, in case we do not find a match.
+ return INVALID_CACHE_INDEX;
}
TextureCacheManager::TextureCacheIndex TextureCacheManager::AppendCache(const TextureCacheManager::TextureInfo& textureInfo)
{
- TextureCacheIndex cacheIndex = static_cast<TextureCacheIndex>(mTextureInfoContainer.size());
+ // If we use EncodedImageBuffer, increase reference during it contains mTextureInfoContainer.
+ // This reference will be decreased when we call RemoveCache
+ if(textureInfo.url.GetProtocolType() == VisualUrl::BUFFER)
+ {
+ UseExternalResource(textureInfo.url);
+ }
+
+ TextureHash hash = textureInfo.hash;
+ TextureId id = textureInfo.textureId;
+
+ // Insert TextureHash container first
+ // Find exist list -or- Create new list.
+ std::vector<TextureId>& idList = mTextureHashContainer[hash];
+ // We already assume that list doesn't contain id. just emplace back
+ idList.emplace_back(id);
+
+ // Insert TextureInfo back of mTextureInfoContainer.
+ TextureCacheIndex cacheIndex = TextureCacheIndex(TextureCacheIndexType::TEXTURE_CACHE_INDEX_TYPE_LOCAL, mTextureInfoContainer.size());
mTextureInfoContainer.emplace_back(textureInfo);
+
+ // Add converter id --> cacheIndex
+ // NOTE : We should assume that id already generated by GenerateTextureId function.
+ mTextureIdConverter[id] = cacheIndex;
+
return cacheIndex;
}
{
TextureCacheIndex textureInfoIndex = GetCacheIndexFromId(textureId);
+ bool removeTextureInfo = false;
+
if(textureInfoIndex != INVALID_CACHE_INDEX)
{
- TextureInfo& textureInfo(mTextureInfoContainer[textureInfoIndex]);
- DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureCacheManager::Remove(textureId:%d) url:%s\n cacheIdx:%d loadState:%s reference count = %d\n", textureId, textureInfo.url.GetUrl().c_str(), textureInfoIndex, GET_LOAD_STATE_STRING(textureInfo.loadState), textureInfo.referenceCount);
+ TextureInfo& textureInfo(mTextureInfoContainer[textureInfoIndex.GetIndex()]);
+
+ DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureCacheManager::Remove(textureId:%d) url:%s\n cacheIdx:%d loadState:%s reference count = %d\n", textureId, textureInfo.url.GetUrl().c_str(), textureInfoIndex.GetIndex(), GET_LOAD_STATE_STRING(textureInfo.loadState), textureInfo.referenceCount);
// Decrement the reference count and check if this is the last user of this Texture.
if(--textureInfo.referenceCount <= 0)
{
// This is the last remove for this Texture.
textureInfo.referenceCount = 0;
- bool removeTextureInfo = false;
// If loaded, we can remove the TextureInfo and the Atlas (if atlased).
if(textureInfo.loadState == LoadState::UPLOADED)
}
removeTextureInfo = true;
}
- else if(textureInfo.loadState == LoadState::LOADING)
+ else if(textureInfo.loadState == LoadState::LOADING || textureInfo.loadState == LoadState::MASK_APPLYING)
{
// We mark the textureInfo for removal.
// Once the load has completed, this method will be called again.
// If url location is BUFFER, decrease reference count of EncodedImageBuffer.
if(textureInfo.url.IsBufferResource())
{
- RemoveExternalEncodedImageBuffer(textureInfo.url.GetUrl());
+ RemoveEncodedImageBuffer(textureInfo.url.GetUrl());
}
+
// Permanently remove the textureInfo struct.
- mTextureInfoContainer.erase(mTextureInfoContainer.begin() + textureInfoIndex);
+
+ // Step 1. remove current textureId information in mTextureHashContainer.
+ RemoveHashId(textureInfo.hash, textureId);
+ // Step 2. make textureId is not using anymore. After this job, we can reuse textureId.
+ mTextureIdConverter.Remove(textureId);
+ }
+ }
+ }
+
+ // Post removal process to avoid mTextureInfoContainer reference problems.
+ if(removeTextureInfo)
+ {
+ // Step 3. swap last data of TextureInfoContainer, and pop_back.
+ RemoveTextureInfoByIndex(mTextureInfoContainer, textureInfoIndex);
+ }
+}
+
+void TextureCacheManager::RemoveHashId(const TextureCacheManager::TextureHash& textureHash, const TextureCacheManager::TextureId& textureId)
+{
+ auto hashIterator = mTextureHashContainer.find(textureHash);
+ if(hashIterator != mTextureHashContainer.end())
+ {
+ auto hashIdList = hashIterator->second;
+ const auto& hashIdIterator = std::find(hashIdList.cbegin(), hashIdList.cend(), textureId);
+ if(hashIdIterator != hashIdList.cend())
+ {
+ hashIdList.erase(hashIdIterator);
+ if(hashIdList.size() == 0)
+ {
+ // If id list in current hash is empty, remove it self in the container.
+ mTextureHashContainer.erase(hashIterator);
}
}
}
*/
// EXTERNAL INCLUDES
+#include <dali/devel-api/common/free-list.h>
#include <dali/public-api/adaptor-framework/encoded-image-buffer.h>
+#include <unordered_map>
// INTERNAL INCLUDES
#include <dali-toolkit/internal/texture-manager/texture-manager-type.h>
* You can Convert TextureId into TextureCacheIndex by this class.
*
* Also, You can store external TextureSet or EncodedImageBuffer here.
+ *
+ * There are 3 type of CachedContainer in this manager
+ * - mTextureInfoContainer : Cache all kind of textures that need some load/upload jobs.
+ * All kind of images that visual using (not vector image) will be stored here.
+ * This container will use TEXTURE_CACHE_INDEX_TYPE_LOCAL
+ *
+ * - mExternalTextures : External appended TextureSet cache container.
+ * External TextureSet can be Something like NativeImageSource, FrameBuffer and PixelData.
+ * This container will use TEXTURE_CACHE_INDEX_TYPE_TEXTURE
+ * The textureId will be used for VisualUrl. ex) dali://1
+ *
+ * - mEncodedImageBuffers : External appended EncodedImageBuffer cache container.
+ * This container will use TEXTURE_CACHE_INDEX_TYPE_BUFFER
+ * The bufferId will be used for VisualUrl. ex) enbuf://1
+ * Note that this bufferId is not equal with textureId in mTextureInfoContainer.
*/
class TextureCacheManager
{
public:
// Copy enum and types and const values that TextureCacheManager will use.
+ using TextureCacheIndexType = TextureManagerType::TextureCacheIndexType;
+ using TextureCacheIndexData = TextureManagerType::TextureCacheIndexData;
+
using TextureId = TextureManagerType::TextureId;
using TextureCacheIndex = TextureManagerType::TextureCacheIndex;
using TextureHash = TextureManagerType::TextureHash;
/**
* @brief Get the current state of a texture
+ * @note This API doesn't consider encodedimagebuffer.
* @param[in] textureId The texture id to query
* @return The loading state if the texture is valid, or NOT_STARTED if the textureId
* is not valid.
/**
* @brief Get the current state of a texture
+ * @note This API doesn't consider external & encodedimagebuffer.
* @param[in] textureId The texture id to query
* @return The loading state if the texture is valid, or NOT_STARTED if the textureId
* is not valid.
/**
* @brief Get the encoded image buffer
- * @param[in] textureId The textureId to look up
- * @return the encoded image buffer, or an empty handle if textureId is not valid
+ * @param[in] bufferId The bufferId to look up
+ * @return the encoded image buffer, or an empty handle if bufferId is not valid
*/
- EncodedImageBuffer GetEncodedImageBuffer(const TextureCacheManager::TextureId& textureId);
+ EncodedImageBuffer GetEncodedImageBuffer(const TextureCacheManager::TextureId& bufferId);
/**
* @brief Get the encoded image buffer by VisualUrl
* @param[in] url The url to look up
* @return the encoded image buffer, or an empty handle if url is not buffer resource or buffer is not valid
*/
- EncodedImageBuffer GetEncodedImageBuffer(const std::string& url);
+ EncodedImageBuffer GetEncodedImageBuffer(const VisualUrl& url);
/**
* Adds an external texture to the texture manager
std::string AddExternalTexture(const TextureSet& texture);
/**
- * Adds an external encoded image buffer to the texture manager
+ * Adds an encoded image buffer to the texture manager
* @param[in] encodedImageBuffer The image buffer to add
* @return string containing the URL for the texture
*/
- std::string AddExternalEncodedImageBuffer(const EncodedImageBuffer& encodedImageBuffer);
+ std::string AddEncodedImageBuffer(const EncodedImageBuffer& encodedImageBuffer);
/**
* Removes an external texture from texture manager
* @param[in] url The string containing the texture to remove
* @return handle to the texture
*/
- TextureSet RemoveExternalTexture(const std::string& url);
+ TextureSet RemoveExternalTexture(const VisualUrl& url);
/**
* Removes an external encoded image buffer from texture manager
* @param[in] url The string containing the encoded image buffer to remove
* @return handle to the encoded image buffer
*/
- EncodedImageBuffer RemoveExternalEncodedImageBuffer(const std::string& url);
+ EncodedImageBuffer RemoveEncodedImageBuffer(const VisualUrl& url);
/**
- * @brief Notify that external textures or external encoded image buffers are used.
+ * @brief Notify that external textures or encoded image buffers are used.
* @param[in] url The URL of the texture to use.
*/
void UseExternalResource(const VisualUrl& url);
// To Generate / Get / Remove TextureId.
/**
- * @brief Generates a new, unique TextureId
- * @return A unique TextureId
+ * @brief Generates a new valid TextureId.
+ * @param[in] textureCacheIndex the index of the cache container. If we don't setup this value, default is INVALID_CACHE_INDEX
+ * @return A TextureId
*/
- TextureCacheManager::TextureId GenerateUniqueTextureId();
+ TextureCacheManager::TextureId GenerateTextureId(const TextureCacheIndex& textureCacheIndex = INVALID_CACHE_INDEX);
/**
* @brief Used to lookup an index into the TextureInfoContainer from a TextureId
* @param[in] samplingMode The SamplingMode to use
* @param[in] useAtlas True if atlased
* @param[in] maskTextureId The masking texture id (or INVALID_TEXTURE_ID)
+ * @param[in] cropToMask True if crop to mask
* @return A hash of the provided data for caching.
*/
TextureCacheManager::TextureHash GenerateHash(
- const std::string& url,
+ const VisualUrl& url,
const Dali::ImageDimensions& size,
const Dali::FittingMode::Type& fittingMode,
const Dali::SamplingMode::Type& samplingMode,
const TextureCacheManager::UseAtlas& useAtlas,
- const TextureCacheManager::TextureId& maskTextureId);
+ const TextureCacheManager::TextureId& maskTextureId,
+ const bool& cropToMask);
/**
* @brief Looks up a cached texture by its hash.
* @param[in] samplingMode The SamplingMode to use
* @param[in] useAtlas True if atlased
* @param[in] maskTextureId Optional texture ID to use to mask this image
- * @param[in] preMultiplyOnLoad If the image's color should be multiplied by it's alpha. Set to OFF if there is no alpha.
+ * @param[in] preMultiplyOnLoad if the image's color should be multiplied by it's alpha. Set to OFF if there is no alpha.
* @param[in] isAnimatedImage True if the texture is from animated image.
- * @return A TextureCacheId of a cached Texture if found. Or INVALID_CACHE_INDEX if not found.
+ * @param[in] cropToMask True if crop to mask
+ * @return A TextureCacheIndex of a cached Texture if found. Or INVALID_CACHE_INDEX if not found.
*/
TextureCacheManager::TextureCacheIndex FindCachedTexture(
const TextureCacheManager::TextureHash& hash,
- const std::string& url,
+ const VisualUrl& url,
const Dali::ImageDimensions& size,
const Dali::FittingMode::Type& fittingMode,
const Dali::SamplingMode::Type& samplingMode,
const TextureCacheManager::UseAtlas& useAtlas,
const TextureCacheManager::TextureId& maskTextureId,
+ const bool& cropToMask,
const TextureCacheManager::MultiplyOnLoad& preMultiplyOnLoad,
- bool isAnimatedImage);
+ const bool& isAnimatedImage);
/**
* @brief Append a Texture to the TextureCacheManager.
* @note This API doesn't check duplication of TextureId.
+ * @note This API doesn't consider external & encodedimagebuffer.
*
* @param[in] textureInfo TextureInfo that want to cache in container.
* @return Index of newly appended texture info.
/**
* @brief Remove a Texture from the TextureCacheManager.
+ * @note This API doesn't consider external & encodedimagebuffer.
*
* Textures are cached and therefore only the removal of the last
* occurrence of a Texture will cause its removal internally.
*/
inline TextureCacheManager::TextureInfo& operator[](const TextureCacheManager::TextureCacheIndex& textureCacheIndex) noexcept
{
- return mTextureInfoContainer[textureCacheIndex];
+ return mTextureInfoContainer[textureCacheIndex.GetIndex()];
}
/**
private:
// Private defined structs.
+ /**
+ * @brief This struct is used to manage the life-cycle of ExternalTexture url.
+ */
struct ExternalTextureInfo
{
ExternalTextureInfo(const TextureCacheManager::TextureId& textureId,
std::int16_t referenceCount;
};
- struct EncodedBufferTextureInfo
+ /**
+ * @brief This struct is used to manage the life-cycle of EncodedImageBuffer url.
+ */
+ struct EncodedImageBufferInfo
{
- EncodedBufferTextureInfo(const TextureCacheManager::TextureId& textureId,
- const EncodedImageBuffer& encodedImageBuffer)
- : textureId(textureId),
+ EncodedImageBufferInfo(const TextureCacheManager::TextureId& bufferId,
+ const TextureCacheManager::TextureHash& bufferHash,
+ const EncodedImageBuffer& encodedImageBuffer)
+ : bufferId(bufferId),
+ bufferHash(bufferHash),
encodedImageBuffer(encodedImageBuffer),
referenceCount(1u)
{
}
- TextureCacheManager::TextureId textureId;
- EncodedImageBuffer encodedImageBuffer;
- std::int16_t referenceCount;
+ TextureCacheManager::TextureId bufferId;
+ TextureCacheManager::TextureHash bufferHash;
+ EncodedImageBuffer encodedImageBuffer;
+ std::int16_t referenceCount;
};
- typedef std::vector<TextureCacheManager::TextureInfo> TextureInfoContainerType; ///< The container type used to manage the life-cycle and caching of Textures
- typedef std::vector<TextureCacheManager::ExternalTextureInfo> ExternalTextureInfoContainerType; ///< The container type used to manage the life-cycle and caching of Textures
- typedef std::vector<TextureCacheManager::EncodedBufferTextureInfo> EncodedBufferTextureInfoContainerType; ///< The container type used to manage the life-cycle and caching of Textures
+ typedef Dali::FreeList TextureIdConverterType; ///< The converter type from TextureId to index of TextureInfoContainer.
+
+ typedef std::unordered_map<TextureCacheManager::TextureHash, std::vector<TextureCacheManager::TextureId>> TextureHashContainerType; ///< The container type used to fast-find the TextureId by TextureHash.
+ typedef std::vector<TextureCacheManager::TextureInfo> TextureInfoContainerType; ///< The container type used to manage the life-cycle and caching of Textures
+ typedef std::vector<TextureCacheManager::ExternalTextureInfo> ExternalTextureInfoContainerType; ///< The container type used to manage the life-cycle and caching of ExternalTexture url
+ typedef std::vector<TextureCacheManager::EncodedImageBufferInfo> EncodedImageBufferInfoContainerType; ///< The container type used to manage the life-cycle and caching of EncodedImageBuffer url
+
+private:
+ // Private API: only used internally
+
+ /**
+ * @brief Used to lookup an index into the ExternalTextureInfoContainer from a textureId
+ * @param[in] textureId The TextureId to look up
+ * @return The cache index
+ */
+ TextureCacheManager::TextureCacheIndex GetCacheIndexFromExternalTextureId(const TextureCacheManager::TextureId& textureId);
+
+ /**
+ * @brief Used to lookup an index into the EncodedImageBufferInfoContainer from a bufferId
+ * @param[in] bufferId The bufferId to look up
+ * @return The cache index
+ */
+ TextureCacheManager::TextureCacheIndex GetCacheIndexFromEncodedImageBufferId(const TextureCacheManager::TextureId& bufferId);
+
+ /**
+ * @brief Looks up a cached encoded image buffer cached by its hash.
+ * If found, the given parameters are used to check there is no hash-collision.
+ * @param[in] hash The hash to look up
+ * @param[in] encodedImageBuffer The image buffer to load
+ * @return A TextureCacheIndex of a cached Texture if found. Or INVALID_CACHE_INDEX if not found.
+ */
+ TextureCacheManager::TextureCacheIndex FindCachedEncodedImageBuffer(const TextureCacheManager::TextureHash& hash, const EncodedImageBuffer& encodedImageBuffer);
+
+ /**
+ * @brief Remove id in HashContainer.
+ * @param[in] hash The hash of the texture/buffer to be delete
+ * @param[in] id The texture/buffer id to be deleted.
+ */
+ void RemoveHashId(const TextureCacheManager::TextureHash& hash, const TextureCacheManager::TextureId& id);
+
+ /**
+ * @brief Remove data from container by the TextureCacheIndex.
+ * It also valiate the TextureIdConverter internally.
+ * We will assume that only valid TextureCacheIndex will come.
+ *
+ * @tparam ContainerType The type of container. It will automatically defined
+ * @param[in] cacheContainer The container that will remove texture info.
+ * @param[in] removeContainerIndex The index of texture info that will remove.
+ */
+ template<class ContainerType>
+ void RemoveTextureInfoByIndex(ContainerType& cacheContainer, const TextureCacheManager::TextureCacheIndex& removeContainerIndex);
private:
/**
*/
TextureCacheManager& operator=(const TextureCacheManager& rhs) = delete;
-private: // Member Variables:
- TextureInfoContainerType mTextureInfoContainer{}; ///< Used to manage the life-cycle and caching of Textures
- ExternalTextureInfoContainerType mExternalTextures{}; ///< Externally provided textures
- EncodedBufferTextureInfoContainerType mEncodedBufferTextures{}; ///< Externally encoded buffer textures
- TextureCacheManager::TextureId mCurrentTextureId; ///< The current value used for the unique Texture Id generation
+private: // Member Variables:
+ TextureIdConverterType mTextureIdConverter{}; ///< Convert TextureId into various container's index.
+ TextureHashContainerType mTextureHashContainer{}; ///< Used to manage the life-cycle and caching of Textures + EncodedImageBuffer by TextureHash
+
+ TextureInfoContainerType mTextureInfoContainer{}; ///< Used to manage the life-cycle and caching of Textures
+ ExternalTextureInfoContainerType mExternalTextures{}; ///< Externally provided textures
+ EncodedImageBufferInfoContainerType mEncodedImageBuffers{}; ///< Externally encoded image buffer
};
} // namespace Internal
mAsyncRemoteLoaders(GetNumberOfRemoteLoaderThreads(), [&]() { return TextureAsyncLoadingHelper(*this); }),
mLifecycleObservers(),
mLoadQueue(),
+ mRemoveQueue(),
mQueueLoadFlag(false)
{
// Initialize the AddOn
{
if(url.IsBufferResource())
{
- const EncodedImageBuffer& encodedImageBuffer = mTextureCacheManager.GetEncodedImageBuffer(url.GetUrl());
+ const EncodedImageBuffer& encodedImageBuffer = mTextureCacheManager.GetEncodedImageBuffer(url);
if(encodedImageBuffer)
{
pixelBuffer = LoadImageFromBuffer(encodedImageBuffer.GetRawBuffer(), desiredSize, fittingMode, samplingMode, orientationCorrection);
TextureCacheIndex cacheIndex = INVALID_CACHE_INDEX;
if(storageType != StorageType::RETURN_PIXEL_BUFFER && useCache)
{
- textureHash = mTextureCacheManager.GenerateHash(url.GetUrl(), desiredSize, fittingMode, samplingMode, useAtlas, maskTextureId);
+ textureHash = mTextureCacheManager.GenerateHash(url, desiredSize, fittingMode, samplingMode, useAtlas, maskTextureId, cropToMask);
// Look up the texture by hash. Note: The extra parameters are used in case of a hash collision.
- cacheIndex = mTextureCacheManager.FindCachedTexture(textureHash, url.GetUrl(), desiredSize, fittingMode, samplingMode, useAtlas, maskTextureId, preMultiplyOnLoad, (animatedImageLoading) ? true : false);
+ cacheIndex = mTextureCacheManager.FindCachedTexture(textureHash, url, desiredSize, fittingMode, samplingMode, useAtlas, maskTextureId, cropToMask, preMultiplyOnLoad, (animatedImageLoading) ? true : false);
}
TextureManager::TextureId textureId = INVALID_TEXTURE_ID;
// Update preMultiplyOnLoad value. It should be changed according to preMultiplied value of the cached info.
preMultiplyOnLoad = mTextureCacheManager[cacheIndex].preMultiplied ? TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD : TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
- DALI_LOG_INFO(gTextureManagerLogFilter, Debug::General, "TextureManager::RequestLoad( url=%s observer=%p ) Using cached texture id@%d, textureId=%d\n", url.GetUrl().c_str(), observer, cacheIndex, textureId);
+ DALI_LOG_INFO(gTextureManagerLogFilter, Debug::General, "TextureManager::RequestLoad( url=%s observer=%p ) Using cached texture id@%d, textureId=%d premultiplied=%d\n", url.GetUrl().c_str(), observer, cacheIndex.GetIndex(), textureId, mTextureCacheManager[cacheIndex].preMultiplied ? 1 : 0);
}
if(textureId == INVALID_TEXTURE_ID) // There was no caching, or caching not required
{
- if(VisualUrl::BUFFER == url.GetProtocolType())
- {
- std::string location = url.GetLocation();
- if(location.size() > 0u)
- {
- TextureId targetId = std::stoi(location);
- const EncodedImageBuffer& encodedImageBuffer = mTextureCacheManager.GetEncodedImageBuffer(targetId);
- if(encodedImageBuffer)
- {
- textureId = targetId;
-
- // Increase EncodedImageBuffer reference during it contains mTextureInfoContainer.
- // TODO! We should change action when reload policy is FORCE.
- // Eunki Hong will fix it after refactoring patch merged.
- mTextureCacheManager.UseExternalResource(url.GetUrl());
- }
- }
- }
-
- if(textureId == INVALID_TEXTURE_ID)
- {
- textureId = mTextureCacheManager.GenerateUniqueTextureId();
- }
+ textureId = mTextureCacheManager.GenerateTextureId();
bool preMultiply = (preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD);
// Cache new texutre, and get cacheIndex.
cacheIndex = mTextureCacheManager.AppendCache(TextureInfo(textureId, maskTextureId, url, desiredSize, contentScale, fittingMode, samplingMode, false, cropToMask, useAtlas, textureHash, orientationCorrection, preMultiply, animatedImageLoading, frameIndex));
- DALI_LOG_INFO(gTextureManagerLogFilter, Debug::General, "TextureManager::RequestLoad( url=%s observer=%p ) New texture, cacheIndex:%d, textureId=%d\n", url.GetUrl().c_str(), observer, cacheIndex, textureId);
+ DALI_LOG_INFO(gTextureManagerLogFilter, Debug::General, "TextureManager::RequestLoad( url=%s observer=%p ) New texture, cacheIndex:%d, textureId=%d\n", url.GetUrl().c_str(), observer, cacheIndex.GetIndex(), textureId);
}
// The below code path is common whether we are using the cache or not.
TextureManager::LoadState::MASK_APPLIED != textureInfo.loadState &&
TextureManager::LoadState::CANCELLED != textureInfo.loadState)
{
- DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Verbose, "TextureManager::RequestLoad( url=%s observer=%p ) ForcedReload cacheIndex:%d, textureId=%d\n", url.GetUrl().c_str(), observer, cacheIndex, textureId);
+ DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Verbose, "TextureManager::RequestLoad( url=%s observer=%p ) ForcedReload cacheIndex:%d, textureId=%d\n", url.GetUrl().c_str(), observer, cacheIndex.GetIndex(), textureId);
textureInfo.loadState = TextureManager::LoadState::NOT_STARTED;
}
void TextureManager::Remove(const TextureManager::TextureId& textureId, TextureUploadObserver* observer)
{
- // Remove textureId in CacheManager.
- mTextureCacheManager.RemoveCache(textureId);
-
- if(observer)
+ if(textureId != INVALID_TEXTURE_ID)
{
- // Remove element from the LoadQueue
- for(auto&& element : mLoadQueue)
+ if(mQueueLoadFlag)
+ {
+ // Remove textureId after NotifyObserver finished
+ mRemoveQueue.PushBack(textureId);
+ }
+ else
{
- if(element.mObserver == observer)
+ // Remove textureId in CacheManager.
+ mTextureCacheManager.RemoveCache(textureId);
+ }
+
+ if(observer)
+ {
+ // Remove element from the LoadQueue
+ for(auto&& element : mLoadQueue)
{
- // Do not erase the item. We will clear it later in ProcessQueuedTextures().
- element.mObserver = nullptr;
- break;
+ if(element.mObserver == observer)
+ {
+ // Do not erase the item. We will clear it later in ProcessLoadQueue().
+ element.mObserver = nullptr;
+ break;
+ }
}
}
}
Devel::PixelBuffer pixelBuffer;
if(url.IsBufferResource())
{
- const EncodedImageBuffer& encodedImageBuffer = mTextureCacheManager.GetEncodedImageBuffer(url.GetUrl());
+ const EncodedImageBuffer& encodedImageBuffer = mTextureCacheManager.GetEncodedImageBuffer(url);
if(encodedImageBuffer)
{
pixelBuffer = LoadImageFromBuffer(encodedImageBuffer.GetRawBuffer(), desiredSize, fittingMode, samplingMode, orientationCorrection);
ObserveTexture(textureInfo, observer);
}
-void TextureManager::ProcessQueuedTextures()
+void TextureManager::ProcessLoadQueue()
{
for(auto&& element : mLoadQueue)
{
mLoadQueue.Clear();
}
+void TextureManager::ProcessRemoveQueue()
+{
+ for(const auto& textureId : mRemoveQueue)
+ {
+ mTextureCacheManager.RemoveCache(textureId);
+ }
+ mRemoveQueue.Clear();
+}
+
void TextureManager::ObserveTexture(TextureManager::TextureInfo& textureInfo,
TextureUploadObserver* observer)
{
void TextureManager::AsyncLoadComplete(const TextureManager::TextureId& textureId, Devel::PixelBuffer pixelBuffer)
{
- DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureManager::AsyncLoadComplete( textureId:%d )\n", textureId);
TextureCacheIndex cacheIndex = mTextureCacheManager.GetCacheIndexFromId(textureId);
+ DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureManager::AsyncLoadComplete( textureId:%d CacheIndex:%d )\n", textureId, cacheIndex.GetIndex());
if(cacheIndex != INVALID_CACHE_INDEX)
{
TextureInfo& textureInfo(mTextureCacheManager[cacheIndex]);
- DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, " textureId:%d Url:%s CacheIndex:%d LoadState: %s\n", textureInfo.textureId, textureInfo.url.GetUrl().c_str(), cacheIndex, GET_LOAD_STATE_STRING(textureInfo.loadState));
+ DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, " textureId:%d Url:%s CacheIndex:%d LoadState: %s\n", textureInfo.textureId, textureInfo.url.GetUrl().c_str(), cacheIndex.GetIndex(), GET_LOAD_STATE_STRING(textureInfo.loadState));
if(textureInfo.loadState != LoadState::CANCELLED)
{
{
// Search the cache, checking if any texture has this texture id as a
// maskTextureId:
- const TextureCacheIndex size = static_cast<TextureCacheIndex>(mTextureCacheManager.size());
+ const std::size_t size = mTextureCacheManager.size();
const bool maskLoadSuccess = maskTextureInfo.loadState == LoadState::LOAD_FINISHED ? true : false;
- for(TextureCacheIndex cacheIndex = 0; cacheIndex < size; ++cacheIndex)
+ // TODO : Refactorize here to not iterate whole cached image.
+ for(TextureCacheIndex cacheIndex = TextureCacheIndex(TextureManagerType::TEXTURE_CACHE_INDEX_TYPE_LOCAL, 0u); cacheIndex.GetIndex() < size; ++cacheIndex.detailValue.index)
{
if(mTextureCacheManager[cacheIndex].maskTextureId == maskTextureInfo.textureId &&
mTextureCacheManager[cacheIndex].loadState == LoadState::WAITING_FOR_MASK)
// invalidating the reference to the textureInfo struct.
// Texture load requests for the same URL are deferred until the end of this
// method.
- DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureManager::NotifyObservers() textureId:%d url:%s loadState:%s\n", textureId, textureInfo.url.GetUrl().c_str(), GET_LOAD_STATE_STRING(textureInfo.loadState));
+ DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureManager::NotifyObservers() textureId:%d url:%s loadState:%s\n", textureId, info->url.GetUrl().c_str(), GET_LOAD_STATE_STRING(info->loadState));
// It is possible for the observer to be deleted.
// Disconnect and remove the observer first.
}
mQueueLoadFlag = false;
- ProcessQueuedTextures();
+ ProcessLoadQueue();
+ ProcessRemoveQueue();
if(info->storageType == StorageType::RETURN_PIXEL_BUFFER && info->observerList.Count() == 0)
{
void TextureManager::ObserverDestroyed(TextureUploadObserver* observer)
{
- const TextureCacheIndex count = static_cast<TextureCacheIndex>(mTextureCacheManager.size());
- for(TextureCacheIndex i = 0; i < count; ++i)
+ const std::size_t size = mTextureCacheManager.size();
+ for(TextureCacheIndex cacheIndex = TextureCacheIndex(TextureManagerType::TEXTURE_CACHE_INDEX_TYPE_LOCAL, 0u); cacheIndex.GetIndex() < size; ++cacheIndex.detailValue.index)
{
- TextureInfo& textureInfo(mTextureCacheManager[i]);
+ TextureInfo& textureInfo(mTextureCacheManager[cacheIndex]);
for(TextureInfo::ObserverListType::Iterator j = textureInfo.observerList.Begin();
j != textureInfo.observerList.End();)
{
}
/**
- * @copydoc TextureCacheManager::RemoveExternalEncodedImageBuffer
+ * @copydoc TextureCacheManager::RemoveEncodedImageBuffer
*/
- inline EncodedImageBuffer RemoveExternalEncodedImageBuffer(const std::string& url)
+ inline EncodedImageBuffer RemoveEncodedImageBuffer(const std::string& url)
{
- return mTextureCacheManager.RemoveExternalEncodedImageBuffer(url);
+ return mTextureCacheManager.RemoveEncodedImageBuffer(url);
}
/**
}
/**
- * @copydoc TextureCacheManager::AddExternalEncodedImageBuffer
+ * @copydoc TextureCacheManager::AddEncodedImageBuffer
*/
- inline std::string AddExternalEncodedImageBuffer(const EncodedImageBuffer& encodedImageBuffer)
+ inline std::string AddEncodedImageBuffer(const EncodedImageBuffer& encodedImageBuffer)
{
- return mTextureCacheManager.AddExternalEncodedImageBuffer(encodedImageBuffer);
+ return mTextureCacheManager.AddEncodedImageBuffer(encodedImageBuffer);
}
public: // Load Request API
/**
* @brief Initiate load of textures queued whilst NotifyObservers invoking callbacks.
*/
- void ProcessQueuedTextures();
+ void ProcessLoadQueue();
+
+ /**
+ * @brief Initiate remove of texture queued whilst NotifyObservers invoking callbacks.
+ */
+ void ProcessRemoveQueue();
/**
* Add the observer to the observer list
RoundRobinContainerView<TextureAsyncLoadingHelper> mAsyncLocalLoaders; ///< The Asynchronous image loaders used to provide all local async loads
RoundRobinContainerView<TextureAsyncLoadingHelper> mAsyncRemoteLoaders; ///< The Asynchronous image loaders used to provide all remote async loads
- Dali::Vector<LifecycleObserver*> mLifecycleObservers; ///< Lifecycle observers of texture manager
- Dali::Vector<LoadQueueElement> mLoadQueue; ///< Queue of textures to load after NotifyObservers
- bool mQueueLoadFlag; ///< Flag that causes Load Textures to be queued.
+ Dali::Vector<LifecycleObserver*> mLifecycleObservers; ///< Lifecycle observers of texture manager
+ Dali::Vector<LoadQueueElement> mLoadQueue; ///< Queue of textures to load after NotifyObservers
+ Dali::Vector<TextureManager::TextureId> mRemoveQueue; ///< Queue of textures to remove after NotifyObservers
+ bool mQueueLoadFlag; ///< Flag that causes Load Textures to be queued.
};
} // namespace Internal
*/
namespace TextureManagerType
{
+// Enum!
+
+enum TextureCacheIndexType
+{
+ TEXTURE_CACHE_INDEX_FREE_LIST = 0, ///< Only for FreeList. We should not use this for TextureCacheIndex.
+ TEXTURE_CACHE_INDEX_TYPE_LOCAL = 1,
+ TEXTURE_CACHE_INDEX_TYPE_TEXTURE,
+ TEXTURE_CACHE_INDEX_TYPE_BUFFER,
+ TEXTURE_CACHE_INDEX_TYPE_MASKING, ///< Not implemented yet.
+ TEXTURE_CACHE_INDEX_TYPE_MAX = 7, ///< Maximum number of cache type we can use.
+};
+
+// Union!
+
+/**
+ * @brief standard union type of texture index.
+ * Due to the FreeList can only use for uint32_t and we need to seperate
+ * each index per container type, we can only hold maximum 2^28 textures
+ * at the same time.
+ * 0 ~ 2^28 - 1 : index of FreeList. TextureCacheManager will not use it.
+ * 2^28 ~ 2*2^28 - 1 : index of mTextureInfoContainer, the main texture container.
+ * 2*2^28 ~ 3*2^28 - 1 : index of mExternalTextures.
+ * 3*2^28 ~ 4*2^28 - 1 : index of mEncodedBufferTextures.
+ */
+union TextureCacheIndexData
+{
+ TextureCacheIndexData() = default;
+ constexpr TextureCacheIndexData(const std::uint32_t& index)
+ : indexValue(index)
+ {
+ }
+ constexpr explicit TextureCacheIndexData(const std::int32_t& index)
+ : indexValue(static_cast<std::uint32_t>(index))
+ {
+ }
+ constexpr TextureCacheIndexData(const TextureCacheIndexType& type, const std::uint32_t& index)
+ : detailValue{index, type}
+ {
+ }
+ constexpr TextureCacheIndexData(const TextureCacheIndexData& indexData)
+ : indexValue(indexData.indexValue)
+ {
+ }
+ constexpr TextureCacheIndexData(TextureCacheIndexData&& indexData)
+ : indexValue(indexData.indexValue)
+ {
+ }
+
+ TextureCacheIndexData& operator=(const std::uint32_t& index)
+ {
+ indexValue = index;
+ return *this;
+ }
+ TextureCacheIndexData& operator=(const TextureCacheIndexData& rhs)
+ {
+ indexValue = rhs.indexValue;
+ return *this;
+ }
+ TextureCacheIndexData& operator=(TextureCacheIndexData&& rhs)
+ {
+ indexValue = rhs.indexValue;
+ return *this;
+ }
+
+ constexpr operator std::uint32_t() const
+ {
+ return indexValue;
+ }
+ constexpr operator std::uint32_t()
+ {
+ return indexValue;
+ }
+ constexpr explicit operator std::int32_t() const
+ {
+ return static_cast<std::int32_t>(indexValue);
+ }
+ constexpr explicit operator std::int32_t()
+ {
+ return static_cast<std::int32_t>(indexValue);
+ }
+
+ // Return detailValue.index. - the real index of datailValue.type container
+ constexpr inline std::uint32_t GetIndex() const
+ {
+ return detailValue.index;
+ }
+
+ inline constexpr bool operator==(const TextureCacheIndexData& rhs)
+ {
+ return indexValue == rhs.indexValue;
+ }
+ inline constexpr bool operator<(const TextureCacheIndexData& rhs)
+ {
+ return indexValue < rhs.indexValue;
+ }
+
+ // Data area
+ std::uint32_t indexValue;
+ struct
+ {
+ unsigned int index : 28;
+ TextureCacheIndexType type : 4;
+ } detailValue;
+};
+
// Typedef:
-typedef std::int32_t TextureId; ///< The TextureId type. This is used as a handle to refer to a particular Texture.
-typedef std::int32_t TextureCacheIndex; ///< The TextureCacheIndex type. This is used as a handles to refer to a particular Texture in TextureCacheManager.
- /// Note : For the same Texture, TextureId will not be changed. But TextureCacheIndex can be chaged when TextureCacheManager
- /// Internal container informations changed by Append or Remove.
-typedef std::size_t TextureHash; ///< The type used to store the hash used for Texture caching.
+typedef std::int32_t TextureId; ///< The TextureId type. This is used as a handle to refer to a particular Texture.
+typedef TextureCacheIndexData TextureCacheIndex; ///< The TextureCacheIndex type. This is used as a handles to refer to a particular Texture in TextureCacheManager.
+ /// Note : For the same Texture, TextureId will not be changed. But TextureCacheIndex can be chaged when TextureCacheManager
+ /// Internal container informations changed by Append or Remove.
+typedef std::size_t TextureHash; ///< The type used to store the hash used for Texture caching.
// Constant values:
static constexpr TextureId INVALID_TEXTURE_ID = -1; ///< Used to represent a null TextureId or error
-static constexpr TextureCacheIndex INVALID_CACHE_INDEX = -1; ///< Used to represent a null TextureCacheIndex or error
+static constexpr TextureCacheIndex INVALID_CACHE_INDEX = 0; ///< Used to represent a null TextureCacheIndex or error
// Enum classes:
}
AnimatedImageVisual::AnimatedImageVisual(VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory)
-: Visual::Base(factoryCache, Visual::FittingMode::FIT_KEEP_ASPECT_RATIO, Toolkit::Visual::ANIMATED_IMAGE),
+: Visual::Base(factoryCache, Visual::FittingMode::FILL, Toolkit::Visual::ANIMATED_IMAGE),
mFrameDelayTimer(),
mPlacementActor(),
mImageVisualShaderFactory(shaderFactory),
else if(mImageUrl.IsBufferResource())
{
TextureManager& textureManager = mFactoryCache.GetTextureManager();
- textureManager.RemoveExternalEncodedImageBuffer(mImageUrl.GetUrl());
+ textureManager.RemoveEncodedImageBuffer(mImageUrl.GetUrl());
}
}
/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
void RasterizingTask::Rasterize()
{
- if(mWidth <= 0u || mHeight <= 0u)
+ Devel::PixelBuffer pixelBuffer = mVectorRenderer.Rasterize(mWidth, mHeight);
+ if(!pixelBuffer)
{
- DALI_LOG_ERROR("RasterizingTask::Rasterize: Size is zero!\n");
- return;
- }
-
- Devel::PixelBuffer pixelBuffer = Devel::PixelBuffer::New(mWidth, mHeight, Dali::Pixel::RGBA8888);
-
- uint32_t defaultWidth, defaultHeight;
- mVectorRenderer.GetDefaultSize(defaultWidth, defaultHeight);
-
- float scaleX = static_cast<float>(mWidth) / static_cast<float>(defaultWidth);
- float scaleY = static_cast<float>(mHeight) / static_cast<float>(defaultHeight);
- float scale = scaleX < scaleY ? scaleX : scaleY;
-
- if(!mVectorRenderer.Rasterize(pixelBuffer, scale))
- {
- DALI_LOG_ERROR("RasterizingTask::Rasterize: Rasterize is failed! [%s]\n", mUrl.GetUrl().c_str());
+ DALI_LOG_ERROR("Rasterize is failed! [%s]\n", mUrl.GetUrl().c_str());
return;
}
mDefaultWidth(0),
mDefaultHeight(0),
mPlacementActor(),
- mVisualSize(Vector2::ZERO),
+ mRasterizedSize(Vector2::ZERO),
mLoadFailed(false),
mAttemptAtlasing(false)
{
}
else
{
- // SVG visual needs it's size set before it can be rasterized hence set ResourceReady once on stage
- ResourceReady(Toolkit::Visual::ResourceStatus::READY);
+ if(mImpl->mEventObserver)
+ {
+ // SVG visual needs it's size set before it can be rasterized hence request relayout once on stage
+ mImpl->mEventObserver->RelayoutRequest(*this);
+ }
}
}
mPlacementActor.Reset();
// Reset the visual size to zero so that when adding the actor back to stage the SVG rasterization is forced
- mVisualSize = Vector2::ZERO;
+ mRasterizedSize = Vector2::ZERO;
}
void SvgVisual::GetNaturalSize(Vector2& naturalSize)
{
- naturalSize.x = mDefaultWidth;
- naturalSize.y = mDefaultHeight;
+ if(mLoadFailed && mImpl->mRenderer)
+ {
+ // Load failed, use broken image size
+ auto textureSet = mImpl->mRenderer.GetTextures();
+ if(textureSet && textureSet.GetTextureCount())
+ {
+ auto texture = textureSet.GetTexture(0);
+ if(texture)
+ {
+ naturalSize.x = texture.GetWidth();
+ naturalSize.y = texture.GetHeight();
+ return;
+ }
+ }
+ }
+ else
+ {
+ naturalSize.x = mDefaultWidth;
+ naturalSize.y = mDefaultHeight;
+ }
}
void SvgVisual::DoCreatePropertyMap(Property::Map& map) const
{
if(isLoaded && rasterizedPixelData && IsOnScene())
{
+ if(mDefaultWidth == 0 || mDefaultHeight == 0)
+ {
+ mVectorRenderer.GetDefaultSize(mDefaultWidth, mDefaultHeight);
+ }
+
+ mRasterizedSize.x = static_cast<float>(rasterizedPixelData.GetWidth());
+ mRasterizedSize.y = static_cast<float>(rasterizedPixelData.GetHeight());
+
TextureSet currentTextureSet = mImpl->mRenderer.GetTextures();
if(mImpl->mFlags & Impl::IS_ATLASING_APPLIED)
{
}
else if(!isLoaded || !rasterizedPixelData)
{
+ mLoadFailed = true;
+
Actor actor = mPlacementActor.GetHandle();
if(actor)
{
if(IsOnScene() && !mLoadFailed)
{
- if(visualSize != mVisualSize)
+ if(visualSize != mRasterizedSize || mDefaultWidth == 0 || mDefaultHeight == 0)
{
AddRasterizationTask(visualSize);
- mVisualSize = visualSize;
+ mRasterizedSize = visualSize;
}
}
uint32_t mDefaultWidth;
uint32_t mDefaultHeight;
WeakHandle<Actor> mPlacementActor;
- Vector2 mVisualSize;
+ Vector2 mRasterizedSize;
bool mLoadFailed;
bool mAttemptAtlasing; ///< If true will attempt atlasing, otherwise create unique texture
};
#define DALI_INTERNAL_TOOLKIT_VISUAL_EVENT_OBSERVER_H
/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
*/
virtual void NotifyVisualEvent(Visual::Base& object, Property::Index signalId) = 0;
+ /**
+ * Requests a relayout to the observer.
+ * @param[in] object The connection owner
+ */
+ virtual void RelayoutRequest(Visual::Base& object) = 0;
+
protected:
/**
* constructor
{
// if only one char in string, can only be regular image
const std::size_t count = url.size();
+ VisualUrl::Type returnType = VisualUrl::REGULAR_IMAGE;
if(count > 0)
{
// parsing from the end for better chance of early outs
}
if((offsetFromEnd < sizeof(GIF)) && (currentChar == GIF[offsetFromEnd]))
{
- // early out if GIF as can't be used in N patch for now
+ //find type, but need to be check used in N patch
if(++gifScore == sizeof(GIF))
{
- return VisualUrl::GIF;
+ returnType = VisualUrl::GIF;
}
}
if((offsetFromEnd < sizeof(WEBP)) && (currentChar == WEBP[offsetFromEnd]))
{
- // early out if WEBP as can't be used in N patch for now
if(++webpScore == sizeof(WEBP))
{
- return VisualUrl::WEBP;
+ //find type, but need to be check used in N patch
+ returnType = VisualUrl::WEBP;
}
}
if((offsetFromEnd < sizeof(JSON)) && (currentChar == JSON[offsetFromEnd]))
else
{
// early out, not a valid N/9-patch URL
- return VisualUrl::REGULAR_IMAGE;
+ return returnType;
}
break;
}
else
{
// early out, not a valid N/9-patch URL
- return VisualUrl::REGULAR_IMAGE;
+ return returnType;
}
break;
}
}
}
// if we got here it is a regular image
- return VisualUrl::REGULAR_IMAGE;
+ return returnType;
}
} // namespace
{
const unsigned int TOOLKIT_MAJOR_VERSION = 2;
const unsigned int TOOLKIT_MINOR_VERSION = 1;
-const unsigned int TOOLKIT_MICRO_VERSION = 20;
+const unsigned int TOOLKIT_MICRO_VERSION = 21;
const char* const TOOLKIT_BUILD_DATE = __DATE__ " " __TIME__;
#ifdef DEBUG_ENABLED
"visualType":"TEXT",
"pointSize":6.0,
"textColor":[0.04,0.06,0.13,1.0],
- "fontFamily":"SamsungOneUI",
+ "fontFamily":"BreezeSans",
"fontStyle" : {"weight":"regular"}
},
"unselectedBackgroundVisual":
Name: dali2-toolkit
Summary: Dali 3D engine Toolkit
-Version: 2.1.20
+Version: 2.1.21
Release: 1
Group: System/Libraries
License: Apache-2.0 and BSD-3-Clause and MIT