*/
// CLASS HEADER
-#include "image-visual.h"
+#include <dali-toolkit/internal/visuals/image/image-visual.h>
// EXTERNAL HEADER
#include <cstring> // for strncasecmp
ImageVisual::ImageVisual( VisualFactoryCache& factoryCache )
: Visual::Base( factoryCache ),
+ mImage(),
+ mPixels(),
+ mTextureSet(),
mPixelArea( FULL_TEXTURE_RECT ),
+ mPlacementActor(),
+ mImageUrl(),
+ mNativeFragmentShaderCode(),
mDesiredSize(),
mFittingMode( FittingMode::DEFAULT ),
mSamplingMode( SamplingMode::DEFAULT ),
mWrapModeU( WrapMode::DEFAULT ),
mWrapModeV( WrapMode::DEFAULT ),
- mNativeFragmentShaderCode( ),
mNativeImageFlag( false )
{
}
+ImageVisual::ImageVisual( VisualFactoryCache& factoryCache,
+ const std::string& imageUrl,
+ ImageDimensions size,
+ FittingMode::Type fittingMode,
+ Dali::SamplingMode::Type samplingMode )
+: Visual::Base( factoryCache ),
+ mImage(),
+ mPixels(),
+ mTextureSet(),
+ mPixelArea( FULL_TEXTURE_RECT ),
+ mPlacementActor(),
+ mImageUrl( imageUrl ),
+ mNativeFragmentShaderCode(),
+ mDesiredSize( size ),
+ mFittingMode( fittingMode ),
+ mSamplingMode( samplingMode ),
+ mWrapModeU( WrapMode::DEFAULT ),
+ mWrapModeV( WrapMode::DEFAULT ),
+ mNativeImageFlag( false )
+{
+}
+
+ImageVisual::ImageVisual( VisualFactoryCache& factoryCache, const Image& image )
+: Visual::Base( factoryCache ),
+ mImage( image ),
+ mPixels(),
+ mPixelArea( FULL_TEXTURE_RECT ),
+ mPlacementActor(),
+ mImageUrl(),
+ mNativeFragmentShaderCode(),
+ mDesiredSize(),
+ mFittingMode( FittingMode::DEFAULT ),
+ mSamplingMode( SamplingMode::DEFAULT ),
+ mWrapModeU( WrapMode::DEFAULT ),
+ mWrapModeV( WrapMode::DEFAULT ),
+ mNativeImageFlag( false )
+{
+ NativeImage newNativeImage = NativeImage::DownCast( image );
+ if( newNativeImage )
+ {
+ SetNativeFragmentShaderCode( newNativeImage );
+ mNativeImageFlag = true;
+ }
+ else
+ {
+ mNativeImageFlag = false;
+ }
+}
+
ImageVisual::~ImageVisual()
{
}
Property::Value* fittingValue = propertyMap.Find( Toolkit::ImageVisual::Property::FITTING_MODE, IMAGE_FITTING_MODE );
if( fittingValue )
{
- Scripting::GetEnumerationProperty( *fittingValue, FITTING_MODE_TABLE, FITTING_MODE_TABLE_COUNT, mFittingMode );
+ int value;
+ Scripting::GetEnumerationProperty( *fittingValue, FITTING_MODE_TABLE, FITTING_MODE_TABLE_COUNT, value );
+ mFittingMode = Dali::FittingMode::Type( value );
}
Property::Value* samplingValue = propertyMap.Find( Toolkit::ImageVisual::Property::SAMPLING_MODE, IMAGE_SAMPLING_MODE );
if( samplingValue )
{
- Scripting::GetEnumerationProperty( *samplingValue, SAMPLING_MODE_TABLE, SAMPLING_MODE_TABLE_COUNT, mSamplingMode );
+ int value;
+ Scripting::GetEnumerationProperty( *samplingValue, SAMPLING_MODE_TABLE, SAMPLING_MODE_TABLE_COUNT, value );
+ mSamplingMode = Dali::SamplingMode::Type( value );
}
int desiredWidth = 0;
Property::Value* wrapModeValueU = propertyMap.Find( Toolkit::ImageVisual::Property::WRAP_MODE_U, IMAGE_WRAP_MODE_U );
if( wrapModeValueU )
{
- Scripting::GetEnumerationProperty( *wrapModeValueU, WRAP_MODE_TABLE, WRAP_MODE_TABLE_COUNT, mWrapModeU );
+ int value;
+ Scripting::GetEnumerationProperty( *wrapModeValueU, WRAP_MODE_TABLE, WRAP_MODE_TABLE_COUNT, value );
+ mWrapModeU = Dali::WrapMode::Type( value );
}
Property::Value* wrapModeValueV = propertyMap.Find( Toolkit::ImageVisual::Property::WRAP_MODE_V, IMAGE_WRAP_MODE_V );
if( wrapModeValueV )
{
- Scripting::GetEnumerationProperty( *wrapModeValueV, WRAP_MODE_TABLE, WRAP_MODE_TABLE_COUNT, mWrapModeV );
+ int value;
+ Scripting::GetEnumerationProperty( *wrapModeValueV, WRAP_MODE_TABLE, WRAP_MODE_TABLE_COUNT, value );
+ mWrapModeV = Dali::WrapMode::Type( value );
}
mDesiredSize = ImageDimensions( desiredWidth, desiredHeight );
// if sync loading is required, the loading should start immediately when new image url is set or the actor is off stage
// ( for on-stage actor with image url unchanged, resource loading is already finished)
- if( ( !mImpl->mRenderer || imageURLValue) && IsSynchronousResourceLoading() )
+ if( imageURLValue && IsSynchronousResourceLoading() )
{
- DoSynchronousResourceLoading();
- }
-
- // remove old renderer if exit
- if( mImpl->mRenderer )
- {
- if( actor ) //remove old renderer from actor
- {
- actor.RemoveRenderer( mImpl->mRenderer );
- }
- if( !oldImageUrl.empty() ) //clean old renderer from cache
- {
- CleanCache( oldImageUrl );
- }
+ LoadResourceSynchronously();
}
NativeImage nativeImage = NativeImage::DownCast( mImage );
naturalSize = Vector2::ZERO;
}
-Renderer ImageVisual::CreateRenderer() const
+void ImageVisual::CreateRenderer()
{
Geometry geometry;
Shader shader;
// Renderer can't be shared between NativeImage and other image types.
if( !mNativeFragmentShaderCode.empty() )
{
- return CreateNativeImageRenderer();
+ CreateNativeImageRenderer();
+ return;
}
if( !mImpl->mCustomShader )
}
}
- Renderer renderer = Renderer::New( geometry, shader );
-
- return renderer;
+ mImpl->mRenderer = Renderer::New( geometry, shader );
+ // apply the texture set as well so it's only done in one place
+ DALI_ASSERT_DEBUG( mTextureSet );
+ mImpl->mRenderer.SetTextures( mTextureSet );
}
-Renderer ImageVisual::CreateNativeImageRenderer() const
+void ImageVisual::CreateNativeImageRenderer()
{
Geometry geometry;
Shader shader;
}
}
- TextureSet textureSet = TextureSet::New();
- Renderer renderer = Renderer::New( geometry, shader );
- renderer.SetTextures( textureSet );
- return renderer;
+ mImpl->mRenderer = Renderer::New( geometry, shader );
+ // apply the texture set as well so it's only done in one place
+ DALI_ASSERT_DEBUG( mTextureSet );
+ mImpl->mRenderer.SetTextures( mTextureSet );
}
return mImpl->mFlags & Impl::IS_SYNCHRONOUS_RESOURCE_LOADING;
}
-void ImageVisual::DoSynchronousResourceLoading()
+void ImageVisual::LoadResourceSynchronously()
{
if( !mImageUrl.empty() )
{
}
}
-Image ImageVisual::LoadImage( const std::string& url, bool synchronousLoading )
-{
- if( synchronousLoading )
- {
- if( !mPixels )
- {
- // use broken image
- return VisualFactoryCache::GetBrokenVisualImage();
- }
- Atlas image = Atlas::New( mPixels.GetWidth(), mPixels.GetHeight(), mPixels.GetPixelFormat() );
- image.Upload( mPixels, 0, 0 );
- return image;
- }
- else
- {
- ResourceImage resourceImage = Dali::ResourceImage::New( url, mDesiredSize, mFittingMode, mSamplingMode );
- resourceImage.LoadingFinishedSignal().Connect( this, &ImageVisual::OnImageLoaded );
- return resourceImage;
- }
-}
-
-TextureSet ImageVisual::CreateTextureSet( Vector4& textureRect, const std::string& url, bool synchronousLoading )
+void ImageVisual::CreateTextureSet( Vector4& textureRect, const std::string& url, bool synchronousLoading, bool attemptAtlasing )
{
- TextureSet textureSet;
textureRect = FULL_TEXTURE_RECT;
if( synchronousLoading )
{
if( !mPixels )
{
// use broken image
- textureSet = TextureSet::New();
- TextureSetImage( textureSet, 0u, VisualFactoryCache::GetBrokenVisualImage() );
+ mTextureSet = TextureSet::New();
+ TextureSetImage( mTextureSet, 0u, VisualFactoryCache::GetBrokenVisualImage() );
}
else
{
- textureSet = mFactoryCache.GetAtlasManager()->Add(textureRect, mPixels );
- mImpl->mFlags |= Impl::IS_ATLASING_APPLIED;
- if( !textureSet ) // big image, no atlasing
+ if( attemptAtlasing )
+ {
+ mTextureSet = mFactoryCache.GetAtlasManager()->Add(textureRect, mPixels );
+ mImpl->mFlags |= Impl::IS_ATLASING_APPLIED;
+ }
+ if( !mTextureSet ) // big image, no atlasing or atlasing failed
{
mImpl->mFlags &= ~Impl::IS_ATLASING_APPLIED;
- Atlas image = Atlas::New( mPixels.GetWidth(), mPixels.GetHeight(), mPixels.GetPixelFormat() );
- image.Upload( mPixels, 0, 0 );
- textureSet = TextureSet::New();
- TextureSetImage( textureSet, 0u, image );
+ Texture texture = Texture::New( Dali::TextureType::TEXTURE_2D, mPixels.GetPixelFormat(),
+ mPixels.GetWidth(), mPixels.GetHeight() );
+ texture.Upload( mPixels );
+ mTextureSet = TextureSet::New();
+ mTextureSet.SetTexture( 0u, texture );
}
}
}
else
{
- textureSet = mFactoryCache.GetAtlasManager()->Add(textureRect, url, mDesiredSize, mFittingMode, mSamplingMode );
- mImpl->mFlags |= Impl::IS_ATLASING_APPLIED;
- if( !textureSet ) // big image, no atlasing
+ if( attemptAtlasing )
+ {
+ mTextureSet = mFactoryCache.GetAtlasManager()->Add(textureRect, url, mDesiredSize, mFittingMode, true, this );
+ mImpl->mFlags |= Impl::IS_ATLASING_APPLIED;
+ }
+ if( !mTextureSet ) // big image, no atlasing or atlasing failed
{
mImpl->mFlags &= ~Impl::IS_ATLASING_APPLIED;
ResourceImage resourceImage = Dali::ResourceImage::New( url, mDesiredSize, mFittingMode, mSamplingMode );
resourceImage.LoadingFinishedSignal().Connect( this, &ImageVisual::OnImageLoaded );
- textureSet = TextureSet::New();
- TextureSetImage( textureSet, 0u, resourceImage );
+ mTextureSet = TextureSet::New();
+ TextureSetImage( mTextureSet, 0u, resourceImage );
}
}
{
Sampler sampler = Sampler::New();
sampler.SetWrapMode( mWrapModeU, mWrapModeV );
- textureSet.SetSampler( 0u, sampler );
+ mTextureSet.SetSampler( 0u, sampler );
}
-
- return textureSet;
}
void ImageVisual::InitializeRenderer( const std::string& imageUrl )
mImageUrl = imageUrl;
mImpl->mRenderer.Reset();
+ mImpl->mFlags &= ~Impl::IS_ATLASING_APPLIED;
if( !mImpl->mCustomShader &&
( strncasecmp( imageUrl.c_str(), HTTP_URL, sizeof(HTTP_URL) -1 ) != 0 ) && // ignore remote images
if( !mImpl->mRenderer ) // new renderer is needed
{
Vector4 atlasRect;
- TextureSet textureSet = CreateTextureSet(atlasRect, imageUrl, IsSynchronousResourceLoading() );
- Geometry geometry = CreateGeometry( mFactoryCache, ImageDimensions( 1, 1 ) );
- Shader shader( GetImageShader(mFactoryCache, mImpl->mFlags & Impl::IS_ATLASING_APPLIED, defaultWrapMode) );
- mImpl->mRenderer = Renderer::New( geometry, shader );
- mImpl->mRenderer.SetTextures( textureSet );
+ // texture set has to be created first as we need to know if atlasing succeeded or not
+ // when selecting the shader
+ CreateTextureSet( atlasRect, imageUrl, IsSynchronousResourceLoading(), true );
+ CreateRenderer();
if( mImpl->mFlags & Impl::IS_ATLASING_APPLIED ) // the texture is packed inside atlas
{
{
// for custom shader or remote image, renderer is not cached and atlas is not applied
mImpl->mFlags &= ~Impl::IS_FROM_CACHE;
- mImpl->mRenderer = CreateRenderer();
- Image image = LoadImage( imageUrl, IsSynchronousResourceLoading() );
- ApplyImageToSampler( image );
+ Vector4 atlasRect; // ignored in this case
+ CreateTextureSet( atlasRect, imageUrl, IsSynchronousResourceLoading(), false );
+ CreateRenderer();
}
}
{
mImpl->mFlags &= ~Impl::IS_FROM_CACHE;
- mImpl->mRenderer = CreateRenderer();
+ // don't reuse CreateTextureSet
+ mTextureSet = TextureSet::New();
+ CreateRenderer();
if( image )
{
}
}
+void ImageVisual::UploadCompleted()
+{
+ // Resource image is loaded. If weak handle is holding a placement actor, it is the time to add the renderer to actor.
+ Actor actor = mPlacementActor.GetHandle();
+ if( actor )
+ {
+ actor.AddRenderer( mImpl->mRenderer );
+ // reset the weak handle so that the renderer only get added to actor once
+ mPlacementActor.Reset();
+ }
+}
+
void ImageVisual::DoSetOnStage( Actor& actor )
{
+ mPlacementActor = actor;
+
if( !mImageUrl.empty() )
{
InitializeRenderer( mImageUrl );
mImpl->mRenderer.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, mPixelArea );
}
- actor.AddRenderer( mImpl->mRenderer );
+ if( IsSynchronousResourceLoading() || !(mImpl->mFlags & Impl::IS_ATLASING_APPLIED) )
+ {
+ actor.AddRenderer( mImpl->mRenderer );
+ mPlacementActor.Reset();
+ }
}
void ImageVisual::DoSetOffStage( Actor& actor )
actor.RemoveRenderer( mImpl->mRenderer );
mImpl->mRenderer.Reset();
}
+ mPlacementActor.Reset();
+ mTextureSet.Reset(); // release texture when going offstage
}
void ImageVisual::DoCreatePropertyMap( Property::Map& map ) const
map.Insert( Toolkit::ImageVisual::Property::WRAP_MODE_V, mWrapModeV );
}
+void ImageVisual::DoSetProperty( Dali::Property::Index index, const Dali::Property::Value& propertyValue )
+{
+ // TODO
+}
+
+Dali::Property::Value ImageVisual::DoGetProperty( Dali::Property::Index index )
+{
+ // TODO
+ return Dali::Property::Value();
+}
+
Shader ImageVisual::GetImageShader( VisualFactoryCache& factoryCache, bool atlasing, bool defaultTextureWrapping )
{
Shader shader;
return shader;
}
-void ImageVisual::SetImage( Actor& actor, const std::string& imageUrl, ImageDimensions size, Dali::FittingMode::Type fittingMode, Dali::SamplingMode::Type samplingMode )
-{
- if( mImageUrl != imageUrl )
- {
- std::string oldImageUrl = mImageUrl;
- mImageUrl = imageUrl;
- mDesiredSize = size;
- mFittingMode = fittingMode;
- mSamplingMode = samplingMode;
- mImage.Reset();
-
- if( IsSynchronousResourceLoading() )
- {
- DoSynchronousResourceLoading();
- }
-
- if( mImpl->mRenderer )
- {
- if( GetIsFromCache() ) // if renderer is from cache, remove the old one
- {
- //remove old renderer
- if( actor )
- {
- actor.RemoveRenderer( mImpl->mRenderer );
- }
-
- //clean the cache
- if( !oldImageUrl.empty() )
- {
- CleanCache(oldImageUrl);
- }
-
- if( actor && actor.OnStage() ) // if actor on stage, create a new renderer and apply to actor
- {
- SetOnStage(actor);
- }
- }
- else // if renderer is not from cache, reuse the same renderer and only change the texture
- {
- Image image = LoadImage( imageUrl, IsSynchronousResourceLoading() );
- ApplyImageToSampler( image );
- }
- }
- }
-}
-
-void ImageVisual::SetImage( Actor& actor, const Image& image )
-{
- if( mImage != image )
- {
- NativeImage newNativeImage = NativeImage::DownCast( image );
- bool newRendererFlag = true;
-
- if( newNativeImage && !mNativeImageFlag )
- {
- SetNativeFragmentShaderCode( newNativeImage );
- }
-
- if( ( newNativeImage && mNativeImageFlag ) || ( !newNativeImage && !mNativeImageFlag ) )
- {
- newRendererFlag = false;
- }
-
- if( newNativeImage )
- {
- mNativeImageFlag = true;
- }
- else
- {
- mNativeFragmentShaderCode.clear();
- mNativeImageFlag = false;
- }
-
- mImage = image;
-
- if( mImpl->mRenderer )
- {
- // if renderer is from cache, remove the old one, and create new renderer
- if( GetIsFromCache() )
- {
- //remove old renderer
- if( actor )
- {
- actor.RemoveRenderer( mImpl->mRenderer );
- }
-
- //clean the cache
- if( !mImageUrl.empty() )
- {
- CleanCache(mImageUrl);
- }
- mImageUrl.clear();
-
- if( actor && actor.OnStage() ) // if actor on stage, create a new renderer and apply to actor
- {
- SetOnStage(actor);
- }
- }
- // if input image is nativeImage and mImage is regular image or the reverse, remove the old one, and create new renderer
- else if( newRendererFlag )
- {
- //remove old renderer
- if( actor )
- {
- actor.RemoveRenderer( mImpl->mRenderer );
- }
-
- if( actor && actor.OnStage() ) // if actor on stage, create a new renderer and apply to actor
- {
- SetOnStage(actor);
- }
- }
- else // if renderer is not from cache, reuse the same renderer and only change the texture
- {
- ApplyImageToSampler( image );
- }
- }
-
- mImageUrl.clear();
- mDesiredSize = ImageDimensions();
- mFittingMode = FittingMode::DEFAULT;
- mSamplingMode = SamplingMode::DEFAULT;
- }
-}
-
void ImageVisual::ApplyImageToSampler( const Image& image )
{
if( image )
{
- TextureSet textureSet = mImpl->mRenderer.GetTextures();
- if( !textureSet )
- {
- textureSet = TextureSet::New();
- mImpl->mRenderer.SetTextures( textureSet );
- }
- TextureSetImage( textureSet, 0u, image );
+ DALI_ASSERT_DEBUG( mTextureSet ); // texture set should always exist by this time
+
+ TextureSetImage( mTextureSet, 0u, image );
Sampler sampler = Sampler::New();
sampler.SetWrapMode( mWrapModeU, mWrapModeV );
- textureSet.SetSampler( 0u, sampler );
+ mTextureSet.SetSampler( 0u, sampler );
}
}
void ImageVisual::CleanCache(const std::string& url)
{
- TextureSet textureSet = mImpl->mRenderer.GetTextures();
-
- Vector4 atlasRect( 0.f, 0.f, 1.f, 1.f );
- Property::Index index = mImpl->mRenderer.GetPropertyIndex( ATLAS_RECT_UNIFORM_NAME );
- if( index != Property::INVALID_INDEX )
+ if( IsFromCache() )
{
- Property::Value atlasRectValue = mImpl->mRenderer.GetProperty( index );
- atlasRectValue.Get( atlasRect );
- }
+ Vector4 atlasRect( 0.f, 0.f, 1.f, 1.f );
+ Property::Index index = mImpl->mRenderer.GetPropertyIndex( ATLAS_RECT_UNIFORM_NAME );
+ if( index != Property::INVALID_INDEX )
+ {
+ Property::Value atlasRectValue = mImpl->mRenderer.GetProperty( index );
+ atlasRectValue.Get( atlasRect );
+ }
- mImpl->mRenderer.Reset();
- if( mFactoryCache.CleanRendererCache( url ) && index != Property::INVALID_INDEX )
- {
- mFactoryCache.GetAtlasManager()->Remove( textureSet, atlasRect );
+ mImpl->mRenderer.Reset();
+ if( mFactoryCache.CleanRendererCache( url ) && index != Property::INVALID_INDEX )
+ {
+ mFactoryCache.GetAtlasManager()->Remove( mTextureSet, atlasRect );
+ }
}
}