X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=dali-toolkit%2Finternal%2Fvisuals%2Fanimated-image%2Fanimated-image-visual.cpp;h=9693cc834ffa57bc63ced05006c9403064e7cd3c;hb=HEAD;hp=d5dcdaa30c70861e4ca59b2a7d108f97226130a0;hpb=c202bbacd19fb0e552f15f1a4106f207927845c3;p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git diff --git a/dali-toolkit/internal/visuals/animated-image/animated-image-visual.cpp b/dali-toolkit/internal/visuals/animated-image/animated-image-visual.cpp index d5dcdaa..d94e0b5 100644 --- a/dali-toolkit/internal/visuals/animated-image/animated-image-visual.cpp +++ b/dali-toolkit/internal/visuals/animated-image/animated-image-visual.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Samsung Electronics Co., Ltd. + * Copyright (c) 2024 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. @@ -16,11 +16,13 @@ */ // CLASS HEADER -#include "animated-image-visual.h" +#include // EXTERNAL INCLUDES #include +#include #include +#include #include // INTERNAL INCLUDES @@ -31,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -46,7 +49,27 @@ namespace Internal { namespace { -const int CUSTOM_PROPERTY_COUNT(3); // ltr, wrap, pixel area, +const int CUSTOM_PROPERTY_COUNT(5); // ltr, wrap, pixel area, crop to mask, mask texture ratio + +// fitting modes +DALI_ENUM_TO_STRING_TABLE_BEGIN(FITTING_MODE) + DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::FittingMode, SHRINK_TO_FIT) + DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::FittingMode, SCALE_TO_FILL) + DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::FittingMode, FIT_WIDTH) + DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::FittingMode, FIT_HEIGHT) + DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::FittingMode, DEFAULT) +DALI_ENUM_TO_STRING_TABLE_END(FITTING_MODE) + +// sampling modes +DALI_ENUM_TO_STRING_TABLE_BEGIN(SAMPLING_MODE) + DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::SamplingMode, BOX) + DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::SamplingMode, NEAREST) + DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::SamplingMode, LINEAR) + DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::SamplingMode, BOX_THEN_NEAREST) + DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::SamplingMode, BOX_THEN_LINEAR) + DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::SamplingMode, NO_FILTER) + DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::SamplingMode, DONT_CARE) +DALI_ENUM_TO_STRING_TABLE_END(SAMPLING_MODE) // stop behavior DALI_ENUM_TO_STRING_TABLE_BEGIN(STOP_BEHAVIOR) @@ -83,6 +106,8 @@ static constexpr Vector4 FULL_TEXTURE_RECT(0.f, 0.f, 1.f, 1.f); static constexpr auto LOOP_FOREVER = -1; static constexpr auto FIRST_LOOP = 0u; +constexpr uint32_t TEXTURE_COUNT_FOR_GPU_ALPHA_MASK = 2u; + #if defined(DEBUG_ENABLED) Debug::Filter* gAnimImgLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_ANIMATED_IMAGE"); #endif @@ -121,7 +146,7 @@ Debug::Filter* gAnimImgLogFilter = Debug::Filter::New(Debug::NoLogging, false, " AnimatedImageVisualPtr AnimatedImageVisual::New(VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, const VisualUrl& imageUrl, const Property::Map& properties) { - AnimatedImageVisualPtr visual(new AnimatedImageVisual(factoryCache, shaderFactory)); + AnimatedImageVisualPtr visual(new AnimatedImageVisual(factoryCache, shaderFactory, ImageDimensions())); visual->InitializeAnimatedImage(imageUrl); visual->SetProperties(properties); @@ -132,7 +157,7 @@ AnimatedImageVisualPtr AnimatedImageVisual::New(VisualFactoryCache& factoryCache AnimatedImageVisualPtr AnimatedImageVisual::New(VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, const Property::Array& imageUrls, const Property::Map& properties) { - AnimatedImageVisualPtr visual(new AnimatedImageVisual(factoryCache, shaderFactory)); + AnimatedImageVisualPtr visual(new AnimatedImageVisual(factoryCache, shaderFactory, ImageDimensions())); visual->mImageUrls = new ImageCache::UrlList(); visual->mImageUrls->reserve(imageUrls.Count()); @@ -151,9 +176,9 @@ AnimatedImageVisualPtr AnimatedImageVisual::New(VisualFactoryCache& factoryCache return visual; } -AnimatedImageVisualPtr AnimatedImageVisual::New(VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, const VisualUrl& imageUrl) +AnimatedImageVisualPtr AnimatedImageVisual::New(VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, const VisualUrl& imageUrl, ImageDimensions size) { - AnimatedImageVisualPtr visual(new AnimatedImageVisual(factoryCache, shaderFactory)); + AnimatedImageVisualPtr visual(new AnimatedImageVisual(factoryCache, shaderFactory, size)); visual->InitializeAnimatedImage(imageUrl); visual->Initialize(); @@ -163,8 +188,24 @@ AnimatedImageVisualPtr AnimatedImageVisual::New(VisualFactoryCache& factoryCache void AnimatedImageVisual::InitializeAnimatedImage(const VisualUrl& imageUrl) { - mImageUrl = imageUrl; + mImageUrl = imageUrl; mAnimatedImageLoading = AnimatedImageLoading::New(imageUrl.GetUrl(), imageUrl.IsLocalResource()); + + // If we fail to load the animated image, we will try to load as a normal image. + if(!mAnimatedImageLoading) + { + mImageUrls = new ImageCache::UrlList(); + mImageUrls->reserve(SINGLE_IMAGE_COUNT); + + for(unsigned int i = 0; i < SINGLE_IMAGE_COUNT; ++i) + { + ImageCache::UrlStore urlStore; + urlStore.mTextureId = TextureManager::INVALID_TEXTURE_ID; + urlStore.mUrl = imageUrl; + mImageUrls->push_back(urlStore); + } + mFrameCount = SINGLE_IMAGE_COUNT; + } } void AnimatedImageVisual::CreateImageCache() @@ -175,7 +216,7 @@ void AnimatedImageVisual::CreateImageCache() if(mAnimatedImageLoading) { - mImageCache = new RollingAnimatedImageCache(textureManager, mAnimatedImageLoading, *this, mCacheSize, mBatchSize, IsSynchronousLoadingRequired()); + mImageCache = new RollingAnimatedImageCache(textureManager, mDesiredSize, mFittingMode, mSamplingMode, mAnimatedImageLoading, mMaskingData, *this, mCacheSize, mBatchSize, mWrapModeU, mWrapModeV, IsSynchronousLoadingRequired(), IsPreMultipliedAlphaEnabled()); } else if(mImageUrls) { @@ -186,22 +227,22 @@ void AnimatedImageVisual::CreateImageCache() uint16_t cacheSize = std::max(std::min(std::max(batchSize, mCacheSize), numUrls), MINIMUM_CACHESIZE); if(cacheSize < numUrls) { - mImageCache = new RollingImageCache(textureManager, *mImageUrls, *this, cacheSize, batchSize, mFrameDelay); + mImageCache = new RollingImageCache(textureManager, mDesiredSize, mFittingMode, mSamplingMode, *mImageUrls, mMaskingData, *this, cacheSize, batchSize, mFrameDelay, IsPreMultipliedAlphaEnabled()); } else { - mImageCache = new FixedImageCache(textureManager, *mImageUrls, *this, batchSize, mFrameDelay); + mImageCache = new FixedImageCache(textureManager, mDesiredSize, mFittingMode, mSamplingMode, *mImageUrls, mMaskingData, *this, batchSize, mFrameDelay, IsPreMultipliedAlphaEnabled()); } } - if(!mImageCache) + if(DALI_UNLIKELY(!mImageCache)) { DALI_LOG_ERROR("mImageCache is null\n"); } } -AnimatedImageVisual::AnimatedImageVisual(VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory) -: Visual::Base(factoryCache, Visual::FittingMode::FIT_KEEP_ASPECT_RATIO, Toolkit::Visual::ANIMATED_IMAGE), +AnimatedImageVisual::AnimatedImageVisual(VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, ImageDimensions desiredSize) +: Visual::Base(factoryCache, Visual::FittingMode::DONT_CARE, Toolkit::Visual::ANIMATED_IMAGE), mFrameDelayTimer(), mPlacementActor(), mImageVisualShaderFactory(shaderFactory), @@ -219,15 +260,20 @@ AnimatedImageVisual::AnimatedImageVisual(VisualFactoryCache& factoryCache, Image mCurrentLoopIndex(FIRST_LOOP), mLoadPolicy(Toolkit::ImageVisual::LoadPolicy::ATTACHED), mReleasePolicy(Toolkit::ImageVisual::ReleasePolicy::DETACHED), + mMaskingData(), + mDesiredSize(desiredSize), mFrameCount(0), mImageSize(), mActionStatus(DevelAnimatedImageVisual::Action::PLAY), mWrapModeU(WrapMode::DEFAULT), mWrapModeV(WrapMode::DEFAULT), + mFittingMode(FittingMode::VISUAL_FITTING), + mSamplingMode(SamplingMode::BOX_THEN_LINEAR), mStopBehavior(DevelImageVisual::StopBehavior::CURRENT_FRAME), mStartFirstFrame(false), mIsJumpTo(false) { + EnablePreMultipliedAlpha(mFactoryCache.GetPreMultiplyOnLoad()); } AnimatedImageVisual::~AnimatedImageVisual() @@ -236,7 +282,10 @@ AnimatedImageVisual::~AnimatedImageVisual() // If this is animated image, clear cache. Else if this is single frame image, this is affected be release policy. if(mFrameCount > SINGLE_IMAGE_COUNT || mReleasePolicy != Toolkit::ImageVisual::ReleasePolicy::NEVER) { - mImageCache->ClearCache(); + if(DALI_LIKELY(mImageCache)) + { + mImageCache->ClearCache(); + } } delete mImageCache; delete mImageUrls; @@ -244,15 +293,56 @@ AnimatedImageVisual::~AnimatedImageVisual() void AnimatedImageVisual::GetNaturalSize(Vector2& naturalSize) { + if(mDesiredSize.GetWidth() > 0 && mDesiredSize.GetHeight() > 0) + { + if(mImpl->mRenderer) + { + auto textureSet = mImpl->mRenderer.GetTextures(); + if(textureSet && textureSet.GetTextureCount()) + { + auto texture = textureSet.GetTexture(0); + if(texture) + { + Dali::Vector2 textureSize; + textureSize.x = texture.GetWidth(); + textureSize.y = texture.GetHeight(); + if(textureSize != Vector2::ZERO) + { + naturalSize = textureSize; + return; + } + } + } + } + + naturalSize.x = mDesiredSize.GetWidth(); + naturalSize.y = mDesiredSize.GetHeight(); + return; + } + + naturalSize = Vector2::ZERO; if(mImageSize.GetWidth() == 0 && mImageSize.GetHeight() == 0) { - if(mImageUrl.IsValid()) + if(mMaskingData && mMaskingData->mAlphaMaskUrl.IsValid() && + mMaskingData->mCropToMask) + { + ImageDimensions dimensions = Dali::GetClosestImageSize(mMaskingData->mAlphaMaskUrl.GetUrl()); + if(dimensions != ImageDimensions(0, 0)) + { + mImageSize = dimensions; + naturalSize.x = dimensions.GetWidth(); + naturalSize.y = dimensions.GetHeight(); + return; + } + } + + if(mImageUrl.IsValid() && mAnimatedImageLoading) { mImageSize = mAnimatedImageLoading.GetImageSize(); } else if(mImageUrls && mImageUrls->size() > 0) { - mImageSize = Dali::GetClosestImageSize((*mImageUrls)[0].mUrl); + mImageSize = Dali::GetClosestImageSize((*mImageUrls)[0].mUrl.GetUrl()); } } @@ -278,7 +368,7 @@ void AnimatedImageVisual::DoCreatePropertyMap(Property::Map& map) const Property::Array urls; for(unsigned int i = 0; i < mImageUrls->size(); ++i) { - urls.Add((*mImageUrls)[i].mUrl); + urls.Add((*mImageUrls)[i].mUrl.GetUrl()); } Property::Value value(const_cast(urls)); map.Insert(Toolkit::ImageVisual::Property::URL, value); @@ -293,18 +383,49 @@ void AnimatedImageVisual::DoCreatePropertyMap(Property::Map& map) const map.Insert(Toolkit::ImageVisual::Property::FRAME_DELAY, static_cast(mFrameDelay)); map.Insert(Toolkit::DevelImageVisual::Property::LOOP_COUNT, static_cast(mLoopCount)); map.Insert(Toolkit::DevelImageVisual::Property::CURRENT_FRAME_NUMBER, (mImageCache) ? static_cast(mImageCache->GetCurrentFrameIndex()) : -1); - map.Insert(Toolkit::DevelImageVisual::Property::TOTAL_FRAME_NUMBER, (mImageCache) ? static_cast((mAnimatedImageLoading) ? mAnimatedImageLoading.GetImageCount() : - mImageCache->GetTotalFrameCount()) : -1); + + // This returns -1 until the loading is finished. + auto frameCount = int32_t(mFrameCount); + if(mImageCache && frameCount == 0) + { + frameCount = mImageCache->GetTotalFrameCount(); + + if(frameCount <= int32_t(SINGLE_IMAGE_COUNT) && mAnimatedImageLoading && mAnimatedImageLoading.HasLoadingSucceeded()) + { + frameCount = int32_t(mAnimatedImageLoading.GetImageCount()); + } + else + { + frameCount = -1; + } + } + + map.Insert(Toolkit::DevelImageVisual::Property::TOTAL_FRAME_NUMBER, static_cast(frameCount)); map.Insert(Toolkit::DevelImageVisual::Property::STOP_BEHAVIOR, mStopBehavior); + if(mMaskingData != nullptr) + { + map.Insert(Toolkit::ImageVisual::Property::ALPHA_MASK_URL, mMaskingData->mAlphaMaskUrl.GetUrl()); + map.Insert(Toolkit::ImageVisual::Property::MASK_CONTENT_SCALE, mMaskingData->mContentScaleFactor); + map.Insert(Toolkit::ImageVisual::Property::CROP_TO_MASK, mMaskingData->mCropToMask); + map.Insert(Toolkit::DevelImageVisual::Property::MASKING_TYPE, mMaskingData->mPreappliedMasking ? DevelImageVisual::MaskingType::MASKING_ON_LOADING : DevelImageVisual::MaskingType::MASKING_ON_RENDERING); + } + map.Insert(Toolkit::ImageVisual::Property::LOAD_POLICY, mLoadPolicy); map.Insert(Toolkit::ImageVisual::Property::RELEASE_POLICY, mReleasePolicy); + map.Insert(Toolkit::ImageVisual::Property::FITTING_MODE, mFittingMode); + map.Insert(Toolkit::ImageVisual::Property::SAMPLING_MODE, mSamplingMode); + map.Insert(Toolkit::ImageVisual::Property::DESIRED_WIDTH, mDesiredSize.GetWidth()); + map.Insert(Toolkit::ImageVisual::Property::DESIRED_HEIGHT, mDesiredSize.GetHeight()); } void AnimatedImageVisual::DoCreateInstancePropertyMap(Property::Map& map) const { - // Do nothing + map.Clear(); + map.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::ANIMATED_IMAGE); + map.Insert(Toolkit::ImageVisual::Property::DESIRED_WIDTH, mDesiredSize.GetWidth()); + map.Insert(Toolkit::ImageVisual::Property::DESIRED_HEIGHT, mDesiredSize.GetHeight()); } void AnimatedImageVisual::OnDoAction(const Dali::Property::Index actionId, const Dali::Property::Value& attributes) @@ -337,7 +458,7 @@ void AnimatedImageVisual::OnDoAction(const Dali::Property::Index actionId, const { // STOP reset functionality will actually be done in a future change // Stop will be executed on next timer tick - mActionStatus = DevelAnimatedImageVisual::Action::STOP; + mActionStatus = DevelAnimatedImageVisual::Action::STOP; mCurrentLoopIndex = FIRST_LOOP; if(IsOnScene()) { @@ -413,6 +534,22 @@ void AnimatedImageVisual::DoSetProperties(const Property::Map& propertyMap) { DoSetProperty(Toolkit::DevelImageVisual::Property::STOP_BEHAVIOR, keyValue.second); } + else if(keyValue.first == ALPHA_MASK_URL) + { + DoSetProperty(Toolkit::ImageVisual::Property::ALPHA_MASK_URL, keyValue.second); + } + else if(keyValue.first == MASK_CONTENT_SCALE_NAME) + { + DoSetProperty(Toolkit::ImageVisual::Property::MASK_CONTENT_SCALE, keyValue.second); + } + else if(keyValue.first == CROP_TO_MASK_NAME) + { + DoSetProperty(Toolkit::ImageVisual::Property::CROP_TO_MASK, keyValue.second); + } + else if(keyValue.first == MASKING_TYPE_NAME) + { + DoSetProperty(Toolkit::DevelImageVisual::Property::MASKING_TYPE, keyValue.second); + } else if(keyValue.first == LOAD_POLICY_NAME) { DoSetProperty(Toolkit::ImageVisual::Property::LOAD_POLICY, keyValue.second); @@ -425,6 +562,22 @@ void AnimatedImageVisual::DoSetProperties(const Property::Map& propertyMap) { DoSetProperty(Toolkit::ImageVisual::Property::SYNCHRONOUS_LOADING, keyValue.second); } + else if(keyValue.first == IMAGE_FITTING_MODE) + { + DoSetProperty(Toolkit::ImageVisual::Property::FITTING_MODE, keyValue.second); + } + else if(keyValue.first == IMAGE_SAMPLING_MODE) + { + DoSetProperty(Toolkit::ImageVisual::Property::SAMPLING_MODE, keyValue.second); + } + else if(keyValue.first == IMAGE_DESIRED_WIDTH) + { + DoSetProperty(Toolkit::ImageVisual::Property::DESIRED_WIDTH, keyValue.second); + } + else if(keyValue.first == IMAGE_DESIRED_HEIGHT) + { + DoSetProperty(Toolkit::ImageVisual::Property::DESIRED_HEIGHT, keyValue.second); + } } } // Load image immediately if LOAD_POLICY requires it @@ -511,7 +664,7 @@ void AnimatedImageVisual::DoSetProperty(Property::Index index, if(value.Get(frameDelay)) { mFrameDelay = frameDelay; - if(mImageCache) + if(DALI_LIKELY(mImageCache)) { mImageCache->SetInterval(static_cast(mFrameDelay)); } @@ -545,11 +698,55 @@ void AnimatedImageVisual::DoSetProperty(Property::Index index, value.Get(sync); if(sync) { - mImpl->mFlags |= Impl::IS_SYNCHRONOUS_RESOURCE_LOADING; + mImpl->mFlags |= Visual::Base::Impl::IS_SYNCHRONOUS_RESOURCE_LOADING; } else { - mImpl->mFlags &= ~Impl::IS_SYNCHRONOUS_RESOURCE_LOADING; + mImpl->mFlags &= ~Visual::Base::Impl::IS_SYNCHRONOUS_RESOURCE_LOADING; + } + break; + } + + case Toolkit::ImageVisual::Property::ALPHA_MASK_URL: + { + std::string alphaUrl = ""; + if(value.Get(alphaUrl)) + { + AllocateMaskData(); + mMaskingData->mAlphaMaskUrl = alphaUrl; + } + break; + } + + case Toolkit::ImageVisual::Property::MASK_CONTENT_SCALE: + { + float scale = 1.0f; + if(value.Get(scale)) + { + AllocateMaskData(); + mMaskingData->mContentScaleFactor = scale; + } + break; + } + + case Toolkit::ImageVisual::Property::CROP_TO_MASK: + { + bool crop = false; + if(value.Get(crop)) + { + AllocateMaskData(); + mMaskingData->mCropToMask = crop; + } + break; + } + + case Toolkit::DevelImageVisual::Property::MASKING_TYPE: + { + int maskingType = 0; + if(value.Get(maskingType)) + { + AllocateMaskData(); + mMaskingData->mPreappliedMasking = Toolkit::DevelImageVisual::MaskingType::Type(maskingType) == Toolkit::DevelImageVisual::MaskingType::MASKING_ON_LOADING ? true : false; } break; } @@ -569,14 +766,67 @@ void AnimatedImageVisual::DoSetProperty(Property::Index index, mLoadPolicy = Toolkit::ImageVisual::LoadPolicy::Type(loadPolicy); break; } + + case Toolkit::ImageVisual::Property::FITTING_MODE: + { + int fittingMode = 0; + Scripting::GetEnumerationProperty(value, FITTING_MODE_TABLE, FITTING_MODE_TABLE_COUNT, fittingMode); + mFittingMode = Dali::FittingMode::Type(fittingMode); + break; + } + + case Toolkit::ImageVisual::Property::SAMPLING_MODE: + { + int samplingMode = 0; + Scripting::GetEnumerationProperty(value, SAMPLING_MODE_TABLE, SAMPLING_MODE_TABLE_COUNT, samplingMode); + mSamplingMode = Dali::SamplingMode::Type(samplingMode); + break; + } + + case Toolkit::ImageVisual::Property::DESIRED_WIDTH: + { + float desiredWidth = 0.0f; + if(value.Get(desiredWidth)) + { + mDesiredSize.SetWidth(desiredWidth); + } + else + { + DALI_LOG_ERROR("AnimatedImageVisual: desiredWidth property has incorrect type\n"); + } + break; + } + + case Toolkit::ImageVisual::Property::DESIRED_HEIGHT: + { + float desiredHeight = 0.0f; + if(value.Get(desiredHeight)) + { + mDesiredSize.SetHeight(desiredHeight); + } + else + { + DALI_LOG_ERROR("AnimatedImageVisual: desiredHeight property has incorrect type\n"); + } + break; + } } } void AnimatedImageVisual::DoSetOnScene(Actor& actor) { - mStartFirstFrame = true; - mPlacementActor = actor; + mStartFirstFrame = true; + mPlacementActor = actor; PrepareTextureSet(); + + actor.InheritedVisibilityChangedSignal().Connect(this, &AnimatedImageVisual::OnControlInheritedVisibilityChanged); + + Window window = DevelWindow::Get(actor); + if(window) + { + mPlacementWindow = window; + DevelWindow::VisibilityChangedSignal(window).Connect(this, &AnimatedImageVisual::OnWindowVisibilityChanged); + } } void AnimatedImageVisual::DoSetOffScene(Actor& actor) @@ -592,7 +842,10 @@ void AnimatedImageVisual::DoSetOffScene(Actor& actor) actor.RemoveRenderer(mImpl->mRenderer); if(mReleasePolicy == Toolkit::ImageVisual::ReleasePolicy::DETACHED) { - mImageCache->ClearCache(); // If INVALID_TEXTURE_ID then removal will be attempted on atlas + if(DALI_LIKELY(mImageCache)) + { + mImageCache->ClearCache(); // If INVALID_TEXTURE_ID then removal will be attempted on atlas + } mImpl->mResourceStatus = Toolkit::Visual::ResourceStatus::PREPARING; TextureSet textureSet = TextureSet::New(); @@ -600,9 +853,18 @@ void AnimatedImageVisual::DoSetOffScene(Actor& actor) } mPlacementActor.Reset(); - mStartFirstFrame = false; + mStartFirstFrame = false; mCurrentFrameIndex = FIRST_FRAME_INDEX; - mCurrentLoopIndex = FIRST_LOOP; + mCurrentLoopIndex = FIRST_LOOP; + + actor.InheritedVisibilityChangedSignal().Disconnect(this, &AnimatedImageVisual::OnControlInheritedVisibilityChanged); + + Window window = mPlacementWindow.GetHandle(); + if(window) + { + DevelWindow::VisibilityChangedSignal(window).Disconnect(this, &AnimatedImageVisual::OnWindowVisibilityChanged); + mPlacementWindow.Reset(); + } } void AnimatedImageVisual::OnSetTransform() @@ -624,14 +886,16 @@ void AnimatedImageVisual::UpdateShader() Shader AnimatedImageVisual::GenerateShader() const { - bool defaultWrapMode = mWrapModeU <= WrapMode::CLAMP_TO_EDGE && mWrapModeV <= WrapMode::CLAMP_TO_EDGE; + bool defaultWrapMode = mWrapModeU <= WrapMode::CLAMP_TO_EDGE && mWrapModeV <= WrapMode::CLAMP_TO_EDGE; + bool requiredAlphaMaskingOnRendering = (mMaskingData && !mMaskingData->mMaskImageLoadingFailed) ? !mMaskingData->mPreappliedMasking : false; Shader shader; shader = mImageVisualShaderFactory.GetShader( mFactoryCache, - ImageVisualShaderFeature::FeatureBuilder() + ImageVisualShaderFeatureBuilder() .ApplyDefaultTextureWrapMode(defaultWrapMode) .EnableRoundedCorner(IsRoundedCornerRequired()) - .EnableBorderline(IsBorderlineRequired())); + .EnableBorderline(IsBorderlineRequired()) + .EnableAlphaMaskingOnRendering(requiredAlphaMaskingOnRendering)); return shader; } @@ -644,7 +908,7 @@ void AnimatedImageVisual::OnInitialize() Geometry geometry = mFactoryCache.GetGeometry(VisualFactoryCache::QUAD_GEOMETRY); - mImpl->mRenderer = VisualRenderer::New(geometry, shader); + mImpl->mRenderer = DecoratedVisualRenderer::New(geometry, shader); mImpl->mRenderer.ReserveCustomProperties(CUSTOM_PROPERTY_COUNT); // Register transform properties @@ -661,6 +925,17 @@ void AnimatedImageVisual::OnInitialize() { mImpl->mRenderer.RegisterProperty(PIXEL_AREA_UNIFORM_NAME, mPixelArea); } + + if(mMaskingData) + { + mImpl->mRenderer.RegisterProperty(CROP_TO_MASK_NAME, static_cast(mMaskingData->mCropToMask)); + } + + // Enable PreMultipliedAlpha if it need premultiplied + auto preMultiplyOnLoad = IsPreMultipliedAlphaEnabled() && !mImpl->mCustomShader + ? TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD + : TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY; + EnablePreMultipliedAlpha(preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD); } void AnimatedImageVisual::StartFirstFrame(TextureSet& textureSet, uint32_t firstInterval) @@ -671,6 +946,7 @@ void AnimatedImageVisual::StartFirstFrame(TextureSet& textureSet, uint32_t first if(mImpl->mRenderer) { mImpl->mRenderer.SetTextures(textureSet); + CheckMaskTexture(); Actor actor = mPlacementActor.GetHandle(); if(actor) @@ -699,10 +975,15 @@ void AnimatedImageVisual::StartFirstFrame(TextureSet& textureSet, uint32_t first void AnimatedImageVisual::PrepareTextureSet() { TextureSet textureSet; - if(mImageCache) + if(DALI_LIKELY(mImageCache)) { textureSet = mImageCache->FirstFrame(); } + else + { + // preMultiplied should be false because broken image don't premultiply alpha on load + FrameReady(TextureSet(), 0, false); + } // Check whether synchronous loading is true or false for the first frame. if(textureSet) @@ -721,11 +1002,29 @@ void AnimatedImageVisual::SetImageSize(TextureSet& textureSet) mImageSize.SetWidth(texture.GetWidth()); mImageSize.SetHeight(texture.GetHeight()); } + + if(textureSet.GetTextureCount() > 1u && mMaskingData && mMaskingData->mCropToMask) + { + Texture maskTexture = textureSet.GetTexture(1); + if(maskTexture) + { + mImageSize.SetWidth(std::min(static_cast(mImageSize.GetWidth() * mMaskingData->mContentScaleFactor), maskTexture.GetWidth())); + mImageSize.SetHeight(std::min(static_cast(mImageSize.GetHeight() * mMaskingData->mContentScaleFactor), maskTexture.GetHeight())); + + float textureWidth = std::max(static_cast(texture.GetWidth() * mMaskingData->mContentScaleFactor), Dali::Math::MACHINE_EPSILON_1); + float textureHeight = std::max(static_cast(texture.GetHeight() * mMaskingData->mContentScaleFactor), Dali::Math::MACHINE_EPSILON_1); + Vector2 textureRatio(std::min(static_cast(maskTexture.GetWidth()), textureWidth) / textureWidth, + std::min(static_cast(maskTexture.GetHeight()), textureHeight) / textureHeight); + mImpl->mRenderer.RegisterProperty(MASK_TEXTURE_RATIO_NAME, textureRatio); + } + } } } -void AnimatedImageVisual::FrameReady(TextureSet textureSet, uint32_t interval) +void AnimatedImageVisual::FrameReady(TextureSet textureSet, uint32_t interval, bool preMultiplied) { + EnablePreMultipliedAlpha(preMultiplied); + // When image visual requested to load new frame to mImageCache and it is failed. if(!mImageCache || !textureSet) { @@ -735,7 +1034,10 @@ void AnimatedImageVisual::FrameReady(TextureSet textureSet, uint32_t interval) if(mStartFirstFrame) { - mFrameCount = mImageCache->GetTotalFrameCount(); + if(DALI_LIKELY(mImageCache)) + { + mFrameCount = mImageCache->GetTotalFrameCount(); + } StartFirstFrame(textureSet, interval); } else @@ -747,6 +1049,7 @@ void AnimatedImageVisual::FrameReady(TextureSet textureSet, uint32_t interval) mFrameDelayTimer.SetInterval(interval); } mImpl->mRenderer.SetTextures(textureSet); + CheckMaskTexture(); } } } @@ -756,7 +1059,7 @@ bool AnimatedImageVisual::DisplayNextFrame() TextureSet textureSet; bool continueTimer = false; - if(mImageCache) + if(DALI_LIKELY(mImageCache)) { uint32_t frameIndex = mImageCache->GetCurrentFrameIndex(); @@ -815,6 +1118,7 @@ bool AnimatedImageVisual::DisplayNextFrame() if(mImpl->mRenderer) { mImpl->mRenderer.SetTextures(textureSet); + CheckMaskTexture(); } mFrameDelayTimer.SetInterval(mImageCache->GetFrameInterval(frameIndex)); } @@ -837,8 +1141,13 @@ TextureSet AnimatedImageVisual::SetLoadingFailed() { imageSize = actor.GetProperty(Actor::Property::SIZE).Get(); } - mFactoryCache.UpdateBrokenImageRenderer(mImpl->mRenderer, imageSize); - TextureSet textureSet = mImpl->mRenderer.GetTextures(); + + TextureSet textureSet; + if(DALI_LIKELY(mImpl->mRenderer)) + { + mFactoryCache.UpdateBrokenImageRenderer(mImpl->mRenderer, imageSize); + textureSet = mImpl->mRenderer.GetTextures(); + } if(mFrameDelayTimer) { @@ -851,6 +1160,52 @@ TextureSet AnimatedImageVisual::SetLoadingFailed() return textureSet; } +void AnimatedImageVisual::AllocateMaskData() +{ + if(!mMaskingData) + { + mMaskingData.reset(new TextureManager::MaskingData()); + } +} + +void AnimatedImageVisual::CheckMaskTexture() +{ + if(mMaskingData && !mMaskingData->mPreappliedMasking) + { + bool maskLoadFailed = true; + TextureSet textures = mImpl->mRenderer.GetTextures(); + if(textures && textures.GetTextureCount() >= TEXTURE_COUNT_FOR_GPU_ALPHA_MASK) + { + maskLoadFailed = false; + } + if(mMaskingData->mMaskImageLoadingFailed != maskLoadFailed) + { + mMaskingData->mMaskImageLoadingFailed = maskLoadFailed; + UpdateShader(); + } + } +} + +void AnimatedImageVisual::OnControlInheritedVisibilityChanged(Actor actor, bool visible) +{ + if(!visible && mActionStatus != DevelAnimatedImageVisual::Action::STOP) + { + mActionStatus = DevelAnimatedImageVisual::Action::STOP; + DisplayNextFrame(); + DALI_LOG_INFO(gAnimImgLogFilter, Debug::Verbose, "AnimatedImageVisual::OnControlInheritedVisibilityChanged: invisibile. Pause animation [%p]\n", this); + } +} + +void AnimatedImageVisual::OnWindowVisibilityChanged(Window window, bool visible) +{ + if(!visible && mActionStatus != DevelAnimatedImageVisual::Action::STOP) + { + mActionStatus = DevelAnimatedImageVisual::Action::STOP; + DisplayNextFrame(); + DALI_LOG_INFO(gAnimImgLogFilter, Debug::Verbose, "AnimatedImageVisual::OnWindowVisibilityChanged: invisibile. Pause animation [%p]\n", this); + } +} + } // namespace Internal } // namespace Toolkit