* @details Name "redrawInScalingDown", type Property::BOOLEAN.
* @note It is used in the AnimatedVectorImageVisual. The default is true.
*/
- REDRAW_IN_SCALING_DOWN
+ REDRAW_IN_SCALING_DOWN = ORIENTATION_CORRECTION + 11,
+
+ /**
+ * @brief Whether to apply mask in loading time or not.
+ * @details Name "preappliedMask", type Property::BOOLEAN.
+ * If it is true, mask image is applied on the texture in loading time with CPU.
+ * If it is false, mask image is applied in runtime in shader.
+ * @note It is used in the ImageVisual and AnimatedImageVisual. The default is true.
+ */
+ PREAPPLIED_MASK = ORIENTATION_CORRECTION + 12
};
} //namespace Property
#ifndef IS_REQUIRED_BORDERLINE
#define IS_REQUIRED_BORDERLINE 0
#endif
+#ifndef IS_REQUIRED_ALPHA_MASKING
+#define IS_REQUIRED_ALPHA_MASKING 0
+#endif
#ifndef ATLAS_DEFAULT_WARP
#define ATLAS_DEFAULT_WARP 0
#endif
#endif
uniform sampler2D sTexture;
+
+#if IS_REQUIRED_ALPHA_MASKING
+uniform sampler2D sMaskTexture;
+INPUT mediump vec2 vMaskTexCoord;
+#endif
+
#if ATLAS_DEFAULT_WARP
uniform mediump vec4 uAtlasRect;
#elif ATLAS_CUSTOM_WARP
lowp vec4 textureColor = TEXTURE( sTexture, texCoord ) * vec4( mixColor, 1.0 ) * uColor;
+#if IS_REQUIRED_ALPHA_MASKING
+ mediump float maskAlpha = TEXTURE(sMaskTexture, vMaskTexCoord).a;
+ textureColor.a *= maskAlpha;
+ textureColor.rgb *= mix(1.0, maskAlpha, preMultipliedAlpha);
+#endif
+
#if IS_REQUIRED_ROUNDED_CORNER || IS_REQUIRED_BORDERLINE
// skip most potential calculate for performance
if(abs(vPosition.x) < vOptRectSize.x && abs(vPosition.y) < vOptRectSize.y)
#ifndef IS_REQUIRED_BORDERLINE
#define IS_REQUIRED_BORDERLINE 0
#endif
+#ifndef IS_REQUIRED_ALPHA_MASKING
+#define IS_REQUIRED_ALPHA_MASKING 0
+#endif
INPUT mediump vec2 aPosition;
OUTPUT mediump vec2 vTexCoord;
uniform mediump vec4 cornerRadius;
uniform mediump float cornerRadiusPolicy;
#endif
+
+#if IS_REQUIRED_ALPHA_MASKING
+OUTPUT mediump vec2 vMaskTexCoord;
+uniform lowp float cropToMask;
+uniform mediump vec2 maskTextureRatio;
+#endif
+
uniform mediump vec2 extraSize;
vec4 ComputeVertexPosition()
mediump vec2 vPosition = aPosition * visualSize;
#endif
- vTexCoord = pixelArea.xy + pixelArea.zw * (vPosition.xy / max(vec2(1.0), visualSize) + vec2(0.5));
+
+vec4 finalPixelArea = pixelArea;
+#if IS_REQUIRED_ALPHA_MASKING
+ finalPixelArea = mix(pixelArea,
+ vec4(
+ vec2(0.5) + (pixelArea.xy - vec2(0.5)) * maskTextureRatio,
+ pixelArea.zw * maskTextureRatio
+ ),
+ cropToMask);
+ vMaskTexCoord = pixelArea.xy + pixelArea.zw * (vPosition.xy / max(vec2(1.0), visualSize) + vec2(0.5));
+#endif
+ vTexCoord = finalPixelArea.xy + finalPixelArea.zw * (vPosition.xy / max(vec2(1.0), visualSize) + vec2(0.5));
+
return vec4(vPosition + anchorPoint * visualSize + (visualOffset + origin) * uSize.xy, 0.0, 1.0);
}
static constexpr auto LOOP_FOREVER = -1;
static constexpr auto FIRST_LOOP = 0u;
+const char* const MASK_TEXTURE_RATIO_NAME("maskTextureRatio");
+
#if defined(DEBUG_ENABLED)
Debug::Filter* gAnimImgLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_ANIMATED_IMAGE");
#endif
void AnimatedImageVisual::GetNaturalSize(Vector2& naturalSize)
{
+ naturalSize = Vector2::ZERO;
if(mImageSize.GetWidth() == 0 && mImageSize.GetHeight() == 0)
{
- if(mImageUrl.IsValid())
+ if(mImpl->mRenderer)
{
- if(mAnimatedImageLoading.HasLoadingSucceeded())
+ auto textureSet = mImpl->mRenderer.GetTextures();
+ if(textureSet)
{
- mImageSize = mAnimatedImageLoading.GetImageSize();
- }
- else
- {
- mImageSize = Dali::GetClosestImageSize(mImageUrl.GetUrl());
+ auto texture = textureSet.GetTexture(0);
+ if(texture)
+ {
+ SetImageSize(textureSet);
+ naturalSize.x = texture.GetWidth();
+ naturalSize.y = texture.GetHeight();
+ return;
+ }
}
}
- else if(mImageUrls && mImageUrls->size() > 0)
- {
- mImageSize = Dali::GetClosestImageSize((*mImageUrls)[0].mUrl);
- }
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())
+ {
+ if(mAnimatedImageLoading.HasLoadingSucceeded())
+ {
+ mImageSize = mAnimatedImageLoading.GetImageSize();
+ }
+ else
+ {
+ mImageSize = Dali::GetClosestImageSize(mImageUrl.GetUrl());
+ }
+ }
+ else if(mImageUrls && mImageUrls->size() > 0)
+ {
+ mImageSize = Dali::GetClosestImageSize((*mImageUrls)[0].mUrl);
+ }
}
naturalSize.width = mImageSize.GetWidth();
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::PREAPPLIED_MASK, mMaskingData->mPreappliedMasking);
}
map.Insert(Toolkit::ImageVisual::Property::LOAD_POLICY, mLoadPolicy);
{
DoSetProperty(Toolkit::ImageVisual::Property::CROP_TO_MASK, keyValue.second);
}
+ else if(keyValue.first == PREAPPLIED_MASK_NAME)
+ {
+ DoSetProperty(Toolkit::DevelImageVisual::Property::PREAPPLIED_MASK, keyValue.second);
+ }
else if(keyValue.first == LOAD_POLICY_NAME)
{
DoSetProperty(Toolkit::ImageVisual::Property::LOAD_POLICY, keyValue.second);
break;
}
+ case Toolkit::DevelImageVisual::Property::PREAPPLIED_MASK:
+ {
+ bool preappliedMask = true;
+ if(value.Get(preappliedMask))
+ {
+ AllocateMaskData();
+ mMaskingData->mPreappliedMasking = preappliedMask;
+ }
+ break;
+ }
+
case Toolkit::ImageVisual::Property::RELEASE_POLICY:
{
int releasePolicy = 0;
{
mImpl->mRenderer.RegisterProperty(PIXEL_AREA_UNIFORM_NAME, mPixelArea);
}
+
+ if(mMaskingData)
+ {
+ mImpl->mRenderer.RegisterProperty(CROP_TO_MASK_NAME, static_cast<float>(mMaskingData->mCropToMask));
+ }
}
void AnimatedImageVisual::StartFirstFrame(TextureSet& textureSet, uint32_t firstInterval)
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<uint32_t>(mImageSize.GetWidth() * mMaskingData->mContentScaleFactor), maskTexture.GetWidth()));
+ mImageSize.SetHeight(std::min(static_cast<uint32_t>(mImageSize.GetHeight() * mMaskingData->mContentScaleFactor), maskTexture.GetHeight()));
+
+ float textureWidth = std::max(static_cast<float>(texture.GetWidth() * mMaskingData->mContentScaleFactor), Dali::Math::MACHINE_EPSILON_1);
+ float textureHeight = std::max(static_cast<float>(texture.GetHeight() * mMaskingData->mContentScaleFactor), Dali::Math::MACHINE_EPSILON_1);
+ Vector2 textureRatio(std::min(static_cast<float>(maskTexture.GetWidth()), textureWidth) / textureWidth,
+ std::min(static_cast<float>(maskTexture.GetHeight()), textureHeight) / textureHeight);
+ mImpl->mRenderer.RegisterProperty(MASK_TEXTURE_RATIO_NAME, textureRatio);
+ }
+ }
}
}
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 requiredAlphaMasking = (mMaskingData) ? !mMaskingData->mPreappliedMasking : false;
Shader shader;
shader = mImageVisualShaderFactory.GetShader(
mFactoryCache,
ImageVisualShaderFeature::FeatureBuilder()
- .ApplyDefaultTextureWrapMode(defaultWrapMode)
- .EnableRoundedCorner(IsRoundedCornerRequired())
- .EnableBorderline(IsBorderlineRequired())
- );
+ .ApplyDefaultTextureWrapMode(defaultWrapMode)
+ .EnableRoundedCorner(IsRoundedCornerRequired())
+ .EnableBorderline(IsBorderlineRequired())
+ .EnableAlphaMasking(requiredAlphaMasking));
return shader;
}
const int NATIVE_SHADER_TYPE_OFFSET = VisualFactoryCache::ShaderType::NATIVE_IMAGE_SHADER - VisualFactoryCache::ShaderType::IMAGE_SHADER;
+// enum of required list when we select shader
+enum class ImageVisualRequireFlag : uint32_t
+{
+ DEFAULT = 0,
+ ROUNDED_CORNER = 1 << 0,
+ BORDERLINE = 1 << 1,
+ ALPHA_MASKING = 1 << 2,
+};
+
+static constexpr auto SHADER_TYPE_COUNT = 8u;
+VisualFactoryCache::ShaderType SHADER_TYPE_TABLE[SHADER_TYPE_COUNT] =
+{
+ VisualFactoryCache::IMAGE_SHADER,
+ VisualFactoryCache::IMAGE_SHADER_ROUNDED_CORNER,
+ VisualFactoryCache::IMAGE_SHADER_BORDERLINE,
+ VisualFactoryCache::IMAGE_SHADER_ROUNDED_BORDERLINE,
+ VisualFactoryCache::IMAGE_SHADER_MASKING,
+ VisualFactoryCache::IMAGE_SHADER_ROUNDED_CORNER_MASKING,
+ VisualFactoryCache::IMAGE_SHADER_BORDERLINE_MASKING,
+ VisualFactoryCache::IMAGE_SHADER_ROUNDED_BORDERLINE_MASKING
+};
+
} // unnamed namespace
namespace ImageVisualShaderFeature
mTexture = texture;
return *this;
}
+FeatureBuilder& FeatureBuilder::EnableAlphaMasking(bool enableAlphaMasking)
+{
+ mAlphaMasking = (enableAlphaMasking ? AlphaMasking::ENABLED : AlphaMasking::DISABLED);
+ return *this;
+}
} // namespace ImageVisualShaderFeature
ImageVisualShaderFactory::ImageVisualShaderFactory()
const auto& defaultTextureWrapping = featureBuilder.mDefaultTextureWrapMode;
const auto& roundedCorner = featureBuilder.mRoundedCorner;
const auto& borderline = featureBuilder.mBorderline;
+ const auto& alphaMasking = featureBuilder.mAlphaMasking;
const auto& changeFragmentShader = (featureBuilder.mTexture && DevelTexture::IsNative(featureBuilder.mTexture))
- ? ImageVisualShaderFeature::ChangeFragmentShader::NEED_CHANGE
- : ImageVisualShaderFeature::ChangeFragmentShader::DONT_CHANGE;
+ ? ImageVisualShaderFeature::ChangeFragmentShader::NEED_CHANGE
+ : ImageVisualShaderFeature::ChangeFragmentShader::DONT_CHANGE;
if(atlasing == ImageVisualShaderFeature::TextureAtlas::ENABLED)
{
}
else
{
+ uint32_t shaderTypeFlag = static_cast<uint32_t>(ImageVisualRequireFlag::DEFAULT);
if(roundedCorner == ImageVisualShaderFeature::RoundedCorner::ENABLED)
{
- if(borderline == ImageVisualShaderFeature::Borderline::ENABLED)
- {
- shaderType = VisualFactoryCache::IMAGE_SHADER_ROUNDED_BORDERLINE;
- }
- else
- {
- shaderType = VisualFactoryCache::IMAGE_SHADER_ROUNDED_CORNER;
- }
+ shaderTypeFlag |= static_cast<uint32_t>(ImageVisualRequireFlag::ROUNDED_CORNER);
}
- else
+ if(borderline == ImageVisualShaderFeature::Borderline::ENABLED)
{
- if(borderline == ImageVisualShaderFeature::Borderline::ENABLED)
- {
- shaderType = VisualFactoryCache::IMAGE_SHADER_BORDERLINE;
- }
+ shaderTypeFlag |= static_cast<uint32_t>(ImageVisualRequireFlag::BORDERLINE);
+ }
+ if(alphaMasking == ImageVisualShaderFeature::AlphaMasking::ENABLED)
+ {
+ shaderTypeFlag |= static_cast<uint32_t>(ImageVisualRequireFlag::ALPHA_MASKING);
}
+ shaderType = SHADER_TYPE_TABLE[shaderTypeFlag];
}
if(changeFragmentShader == ImageVisualShaderFeature::ChangeFragmentShader::NEED_CHANGE &&
vertexShaderPrefixList += "#define IS_REQUIRED_BORDERLINE 1\n";
fragmentShaderPrefixList += "#define IS_REQUIRED_BORDERLINE 1\n";
}
+ if(alphaMasking == ImageVisualShaderFeature::AlphaMasking::ENABLED)
+ {
+ vertexShaderPrefixList += "#define IS_REQUIRED_ALPHA_MASKING 1\n";
+ fragmentShaderPrefixList += "#define IS_REQUIRED_ALPHA_MASKING 1\n";
+ }
}
std::string vertexShader = std::string(Dali::Shader::GetVertexShaderPrefix() + vertexShaderPrefixList + SHADER_IMAGE_VISUAL_SHADER_VERT.data());
{
namespace Internal
{
-
/**
* ImageVisualShaderFeature contains feature lists what image visual shader need to know.
*/
};
} // namespace ChangeFragmentShader
+namespace AlphaMasking
+{
+/**
+ * @brief Whether use runtime alpha masking in shader, or not
+ */
+enum Type
+{
+ DISABLED = 0, ///< Image visual doesn't use runtime alpha masking
+ ENABLED ///< Image visual uses runtime alpha masking
+};
+} // namespace AlphaMasking
+
/**
* @brief Collection of current image visual feature. Only use for ImageVisualShaderFactory::GetShader()
*/
mDefaultTextureWrapMode(DefaultTextureWrapMode::APPLY),
mRoundedCorner(RoundedCorner::DISABLED),
mBorderline(Borderline::DISABLED),
+ mAlphaMasking(AlphaMasking::DISABLED),
mTexture()
{
}
FeatureBuilder& EnableRoundedCorner(bool enableRoundedCorner);
FeatureBuilder& EnableBorderline(bool enableBorderline);
FeatureBuilder& SetTextureForFragmentShaderCheck(const Dali::Texture& texture);
+ FeatureBuilder& EnableAlphaMasking(bool enableAlphaMasking);
TextureAtlas::Type mTextureAtlas : 2; ///< Whether use texture with atlas, or not. default as TextureAtlas::DISABLED
DefaultTextureWrapMode::Type mDefaultTextureWrapMode : 2; ///< Whether apply to texture wraping in default, or not. default as DefaultTextureWrapMode::APPLY
RoundedCorner::Type mRoundedCorner : 2; ///< Whether use rounded corner, or not. default as RoundedCorner::DISABLED
Borderline::Type mBorderline : 2; ///< Whether use borderline, or not. default as Borderline::DISABLED
+ AlphaMasking::Type mAlphaMasking : 2; ///< Whether use runtime alpha masking, or not. default as AlphaMasking::DISABLED
Dali::Texture mTexture; ///< Texture to check whether we need to change fragment shader or not
};
-} // namespace ImageVisualShaderFactoryFeature
+} // namespace ImageVisualShaderFeature
/**
* ImageVisualShaderFactory is an object that provides and shares shaders between image visuals
class ImageVisualShaderFactory
{
public:
-
/**
* @brief Constructor
*/
ImageVisualShaderFactory& operator=(const ImageVisualShaderFactory& rhs);
private:
-
/**
* @brief Cached information whether native image should change fragment shader.
* Default it is ChangeFragmentShader::UNDECIDED.
: mAlphaMaskUrl(),
mAlphaMaskId(INVALID_TEXTURE_ID),
mContentScaleFactor(1.0f),
- mCropToMask(true)
+ mCropToMask(true),
+ mPreappliedMasking(true)
{
}
}
else
{
+ Texture maskTexture;
if(maskInfo && maskInfo->mAlphaMaskUrl.IsValid())
{
Devel::PixelBuffer maskPixelBuffer = LoadImageFromFile(maskInfo->mAlphaMaskUrl.GetUrl(), ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::NO_FILTER, true);
if(maskPixelBuffer)
{
- pixelBuffer.ApplyMask(maskPixelBuffer, maskInfo->mContentScaleFactor, maskInfo->mCropToMask);
+ if(!maskInfo->mPreappliedMasking)
+ {
+ PixelData maskPixelData = Devel::PixelBuffer::Convert(maskPixelBuffer); // takes ownership of buffer
+ Texture maskTexture = Texture::New(Dali::TextureType::TEXTURE_2D, maskPixelData.GetPixelFormat(), maskPixelData.GetWidth(), maskPixelData.GetHeight());
+ maskTexture.Upload(maskPixelData);
+ }
+ else
+ {
+ pixelBuffer.ApplyMask(maskPixelBuffer, maskInfo->mContentScaleFactor, maskInfo->mCropToMask);
+ }
}
}
texture.Upload(pixelData);
textureSet = TextureSet::New();
textureSet.SetTexture(0u, texture);
+ if(maskTexture)
+ {
+ textureSet.SetTexture(1u, maskTexture);
+ }
}
}
}
bool cropToMask = false;
if(maskInfo && maskInfo->mAlphaMaskUrl.IsValid())
{
- maskInfo->mAlphaMaskId = RequestMaskLoad(maskInfo->mAlphaMaskUrl);
+ maskInfo->mAlphaMaskId = RequestMaskLoad(maskInfo->mAlphaMaskUrl, maskInfo->mPreappliedMasking ? StorageType::KEEP_PIXEL_BUFFER : StorageType::KEEP_TEXTURE);
alphaMaskId = maskInfo->mAlphaMaskId;
contentScaleFactor = maskInfo->mContentScaleFactor;
cropToMask = maskInfo->mCropToMask;
textureId = RequestLoadInternal(animatedImageLoading.GetUrl(),
alphaMaskId,
contentScaleFactor,
+ cropToMask,
ImageDimensions(),
FittingMode::SCALE_TO_FILL,
SamplingMode::BOX_THEN_LINEAR,
TextureManager::NO_ATLAS,
- cropToMask,
StorageType::UPLOAD_TO_TEXTURE,
textureObserver,
true,
}
else
{
- RequestLoadInternal(url, INVALID_TEXTURE_ID, 1.0f, desiredSize, fittingMode, samplingMode, TextureManager::NO_ATLAS, false, StorageType::RETURN_PIXEL_BUFFER, textureObserver, orientationCorrection, TextureManager::ReloadPolicy::FORCED, preMultiplyOnLoad, Dali::AnimatedImageLoading(), 0u, false);
+ RequestLoadInternal(url, INVALID_TEXTURE_ID, 1.0f, false, desiredSize, fittingMode, samplingMode, TextureManager::NO_ATLAS, StorageType::RETURN_PIXEL_BUFFER, textureObserver, orientationCorrection, TextureManager::ReloadPolicy::FORCED, preMultiplyOnLoad, Dali::AnimatedImageLoading(), 0u, false);
}
return pixelBuffer;
}
else
{
- maskInfo->mAlphaMaskId = RequestMaskLoad(maskInfo->mAlphaMaskUrl);
+ maskInfo->mAlphaMaskId = RequestMaskLoad(maskInfo->mAlphaMaskUrl, maskInfo->mPreappliedMasking ? StorageType::KEEP_PIXEL_BUFFER : StorageType::KEEP_TEXTURE);
textureId = RequestLoad(url,
maskInfo->mAlphaMaskId,
maskInfo->mContentScaleFactor,
TextureManager::ReloadPolicy reloadPolicy,
TextureManager::MultiplyOnLoad& preMultiplyOnLoad)
{
- return RequestLoadInternal(url, INVALID_TEXTURE_ID, 1.0f, desiredSize, fittingMode, samplingMode, useAtlas, false, StorageType::UPLOAD_TO_TEXTURE, observer, orientationCorrection, reloadPolicy, preMultiplyOnLoad, Dali::AnimatedImageLoading(), 0u, true);
+ return RequestLoadInternal(url, INVALID_TEXTURE_ID, 1.0f, false, desiredSize, fittingMode, samplingMode, useAtlas, StorageType::UPLOAD_TO_TEXTURE, observer, orientationCorrection, reloadPolicy, preMultiplyOnLoad, Dali::AnimatedImageLoading(), 0u, true);
}
TextureManager::TextureId TextureManager::RequestLoad(
TextureManager::ReloadPolicy reloadPolicy,
TextureManager::MultiplyOnLoad& preMultiplyOnLoad)
{
- return RequestLoadInternal(url, maskTextureId, contentScale, desiredSize, fittingMode, samplingMode, useAtlas, cropToMask, StorageType::UPLOAD_TO_TEXTURE, observer, orientationCorrection, reloadPolicy, preMultiplyOnLoad, Dali::AnimatedImageLoading(), 0u, true);
+ return RequestLoadInternal(url, maskTextureId, contentScale, cropToMask, desiredSize, fittingMode, samplingMode, useAtlas, StorageType::UPLOAD_TO_TEXTURE, observer, orientationCorrection, reloadPolicy, preMultiplyOnLoad, Dali::AnimatedImageLoading(), 0u, true);
}
-TextureManager::TextureId TextureManager::RequestMaskLoad(const VisualUrl& maskUrl)
+TextureManager::TextureId TextureManager::RequestMaskLoad(const VisualUrl& maskUrl, StorageType storageType)
{
// Use the normal load procedure to get the alpha mask.
auto preMultiply = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
- return RequestLoadInternal(maskUrl, INVALID_TEXTURE_ID, 1.0f, ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::NO_FILTER, NO_ATLAS, false, StorageType::KEEP_PIXEL_BUFFER, NULL, true, TextureManager::ReloadPolicy::CACHED, preMultiply, Dali::AnimatedImageLoading(), 0u, true);
+ return RequestLoadInternal(maskUrl, INVALID_TEXTURE_ID, 1.0f, false, ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::NO_FILTER, NO_ATLAS, storageType, NULL, true, TextureManager::ReloadPolicy::CACHED, preMultiply, Dali::AnimatedImageLoading(), 0u, true);
}
TextureManager::TextureId TextureManager::RequestLoadInternal(
const VisualUrl& url,
TextureId maskTextureId,
float contentScale,
+ bool cropToMask,
const ImageDimensions desiredSize,
FittingMode::Type fittingMode,
Dali::SamplingMode::Type samplingMode,
UseAtlas useAtlas,
- bool cropToMask,
StorageType storageType,
TextureUploadObserver* observer,
bool orientationCorrection,
textureHash = GenerateHash(url.GetUrl(), desiredSize, fittingMode, samplingMode, useAtlas, maskTextureId);
// Look up the texture by hash. Note: The extra parameters are used in case of a hash collision.
- cacheIndex = FindCachedTexture(textureHash, url.GetUrl(), desiredSize, fittingMode, samplingMode, useAtlas, maskTextureId, preMultiplyOnLoad, (animatedImageLoading) ? true : false);
+ cacheIndex = FindCachedTexture(textureHash, url.GetUrl(), desiredSize, fittingMode, samplingMode, useAtlas,
+ storageType, maskTextureId, preMultiplyOnLoad, (animatedImageLoading) ? true : false);
}
TextureManager::TextureId textureId = INVALID_TEXTURE_ID;
}
else if(maskLoadState == LoadState::LOAD_FINISHED)
{
- // Send New Task to Thread
- ApplyMask(textureInfo, textureInfo.maskTextureId);
+ int32_t maskCacheIndex = GetCacheIndexFromId(textureInfo.maskTextureId);
+ if(maskCacheIndex != INVALID_CACHE_INDEX)
+ {
+ TextureInfo& maskTextureInfo(mTextureInfoContainer[maskCacheIndex]);
+ if(maskTextureInfo.storageType == StorageType::KEEP_PIXEL_BUFFER)
+ {
+ // Send New Task to Thread
+ ApplyMask(textureInfo, textureInfo.maskTextureId);
+ }
+ }
+ }
+ else if(maskLoadState == LoadState::UPLOADED)
+ {
+ int32_t maskCacheIndex = GetCacheIndexFromId(textureInfo.maskTextureId);
+ if(maskCacheIndex != INVALID_CACHE_INDEX)
+ {
+ TextureInfo& maskTextureInfo(mTextureInfoContainer[maskCacheIndex]);
+ if(maskTextureInfo.storageType == StorageType::KEEP_TEXTURE)
+ {
+ // Upload image texture. textureInfo.loadState will be UPLOADED.
+ UploadTexture(textureInfo.pixelBuffer, textureInfo);
+ if(maskTextureInfo.textureSet.GetTextureCount() > 0u)
+ {
+ Texture maskTexture = maskTextureInfo.textureSet.GetTexture(0u);
+ textureInfo.textureSet.SetTexture(1u, maskTexture);
+ }
+ // notify mask texture set.
+ NotifyObservers(textureInfo, true);
+ }
+ }
}
}
}
{
NotifyObservers(textureInfo, true);
}
- else
+ else // for the StorageType::KEEP_PIXEL_BUFFER and StorageType::KEEP_TEXTURE
{
// Check if there was another texture waiting for this load to complete
// (e.g. if this was an image mask, and its load is on a different thread)
void TextureManager::CheckForWaitingTexture(TextureInfo& maskTextureInfo)
{
+ if(maskTextureInfo.loadState == LoadState::LOAD_FINISHED &&
+ maskTextureInfo.storageType == StorageType::KEEP_TEXTURE)
+ {
+ // Upload mask texture. textureInfo.loadState will be UPLOADED.
+ UploadTexture(maskTextureInfo.pixelBuffer, maskTextureInfo);
+ }
+
// Search the cache, checking if any texture has this texture id as a
// maskTextureId:
const unsigned int size = mTextureInfoContainer.size();
-
for(unsigned int cacheIndex = 0; cacheIndex < size; ++cacheIndex)
{
if(mTextureInfoContainer[cacheIndex].maskTextureId == maskTextureInfo.textureId &&
if(maskTextureInfo.loadState == LoadState::LOAD_FINISHED)
{
- // Send New Task to Thread
- ApplyMask(textureInfo, maskTextureInfo.textureId);
+ if(maskTextureInfo.storageType == StorageType::KEEP_PIXEL_BUFFER)
+ {
+ // Send New Task to Thread
+ ApplyMask(textureInfo, maskTextureInfo.textureId);
+ }
+ }
+ else if (maskTextureInfo.loadState == LoadState::UPLOADED)
+ {
+ if(maskTextureInfo.storageType == StorageType::KEEP_TEXTURE)
+ {
+ // Upload image texture. textureInfo.loadState will be UPLOADED.
+ UploadTexture(textureInfo.pixelBuffer, textureInfo);
+ if(maskTextureInfo.textureSet.GetTextureCount() > 0u)
+ {
+ Texture maskTexture = maskTextureInfo.textureSet.GetTexture(0u);
+ textureInfo.textureSet.SetTexture(1u, maskTexture);
+ }
+ // notify mask texture set.
+ NotifyObservers(textureInfo, true);
+ }
}
else
{
+ // for the load fail.
textureInfo.pixelBuffer.Reset();
textureInfo.loadState = LoadState::LOAD_FAILED;
NotifyObservers(textureInfo, false);
const FittingMode::Type fittingMode,
const Dali::SamplingMode::Type samplingMode,
const bool useAtlas,
+ StorageType storageType,
TextureId maskTextureId,
TextureManager::MultiplyOnLoad preMultiplyOnLoad,
bool isAnimatedImage)
(maskTextureId == textureInfo.maskTextureId) &&
(size == textureInfo.desiredSize) &&
(isAnimatedImage == textureInfo.isAnimatedImageFormat) &&
+ (storageType == textureInfo.storageType) &&
((size.GetWidth() == 0 && size.GetHeight() == 0) ||
(fittingMode == textureInfo.fittingMode &&
samplingMode == textureInfo.samplingMode)))
{
KEEP_PIXEL_BUFFER,
RETURN_PIXEL_BUFFER,
+ KEEP_TEXTURE,
UPLOAD_TO_TEXTURE
};
TextureManager::TextureId mAlphaMaskId;
float mContentScaleFactor;
bool mCropToMask;
+ bool mPreappliedMasking;
};
using MaskingDataPointer = std::unique_ptr<MaskingData>;
* Requests a masking image to be loaded. This mask is not uploaded to GL,
* instead, it is stored in CPU memory, and can be used for CPU blending.
*/
- TextureId RequestMaskLoad(const VisualUrl& maskUrl);
+ TextureId RequestMaskLoad(const VisualUrl& maskUrl, StorageType storageType);
/**
* @brief Remove a Texture from the TextureManager.
* @param[in] maskTextureId The texture id of an image to use as a mask. If no mask is required, then set
* to INVALID_TEXTURE_ID
* @param[in] contentScale The scaling factor to apply to the content when masking
+ * @param[in] cropToMask Whether to crop the target after masking, or scale the mask to the image before
+ * masking.
* @param[in] desiredSize The size the image is likely to appear at. This can be set to 0,0 for automatic
* @param[in] fittingMode The FittingMode to use
* @param[in] samplingMode The SamplingMode to use
* @param[in] useAtlasing Set to USE_ATLAS to attempt atlasing. If atlasing fails, the image will still be
* loaded, and marked successful, but "useAtlasing" will be set to false in the
* "UploadCompleted" callback from the TextureManagerUploadObserver.
- * @param[in] cropToMask Whether to crop the target after masking, or scale the mask to the image before
- * masking.
* @param[in] storageType, Whether the pixel data is stored in the cache or uploaded to the GPU
* @param[in] observer The client object should inherit from this and provide the "UploadCompleted"
* virtual.
const VisualUrl& url,
TextureId maskTextureId,
float contentScale,
+ bool cropToMask,
const ImageDimensions desiredSize,
FittingMode::Type fittingMode,
Dali::SamplingMode::Type samplingMode,
UseAtlas useAtlas,
- bool cropToMask,
StorageType storageType,
TextureUploadObserver* observer,
bool orientationCorrection,
MultiplyOnLoad& preMultiplyOnLoad,
Dali::AnimatedImageLoading animatedImageLoading,
uint32_t frameIndex,
- bool useCache);
+ bool useCache);
/**
* @brief Get the current state of a texture
* @param[in] fittingMode The FittingMode to use
* @param[in] samplingMode The SamplingMode to use
* @param[in] useAtlas True if atlased
+ * @param[in] storageType, Whether the pixel data is stored in the cache or uploaded to the GPU
* @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] isAnimatedImage True if the texture is from animated image.
const FittingMode::Type fittingMode,
const Dali::SamplingMode::Type samplingMode,
const bool useAtlas,
+ StorageType storageType,
TextureId maskTextureId,
MultiplyOnLoad preMultiplyOnLoad,
bool isAnimatedImage);
IMAGE_SHADER_ROUNDED_CORNER,
IMAGE_SHADER_BORDERLINE,
IMAGE_SHADER_ROUNDED_BORDERLINE,
+ IMAGE_SHADER_MASKING,
+ IMAGE_SHADER_ROUNDED_CORNER_MASKING,
+ IMAGE_SHADER_BORDERLINE_MASKING,
+ IMAGE_SHADER_ROUNDED_BORDERLINE_MASKING,
IMAGE_SHADER_ATLAS_DEFAULT_WRAP,
IMAGE_SHADER_ATLAS_CUSTOM_WRAP,
NATIVE_IMAGE_SHADER,
NATIVE_IMAGE_SHADER_ROUNDED_CORNER,
NATIVE_IMAGE_SHADER_BORDERLINE,
NATIVE_IMAGE_SHADER_ROUNDED_BORDERLINE,
+ NATIVE_IMAGE_SHADER_MASKING,
+ NATIVE_IMAGE_SHADER_ROUNDED_CORNER_MASKING,
+ NATIVE_IMAGE_SHADER_BORDERLINE_MASKING,
+ NATIVE_IMAGE_SHADER_ROUNDED_BORDERLINE_MASKING,
NINE_PATCH_SHADER,
NINE_PATCH_MASK_SHADER,
TEXT_SHADER_MULTI_COLOR_TEXT,
const char* const IMAGE_DESIRED_HEIGHT("desiredHeight");
const char* const ALPHA_MASK_URL("alphaMaskUrl");
const char* const REDRAW_IN_SCALING_DOWN_NAME("redrawInScalingDown");
+const char* const PREAPPLIED_MASK_NAME("preappliedMask");
// Text visual
const char* const TEXT_PROPERTY("text");
extern const char* const IMAGE_DESIRED_HEIGHT;
extern const char* const ALPHA_MASK_URL;
extern const char* const REDRAW_IN_SCALING_DOWN_NAME;
+extern const char* const PREAPPLIED_MASK_NAME;
// Text visual
extern const char* const TEXT_PROPERTY;