2 * Copyright (c) 2017 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include <dali-toolkit/internal/visuals/image/image-visual.h>
22 #include <cstring> // for strlen()
23 #include <dali/public-api/actors/layer.h>
24 #include <dali/public-api/common/stage.h>
25 #include <dali/public-api/images/resource-image.h>
26 #include <dali/public-api/images/native-image.h>
27 #include <dali/devel-api/images/texture-set-image.h>
28 #include <dali/devel-api/adaptor-framework/image-loading.h>
29 #include <dali/devel-api/scripting/enum-helper.h>
30 #include <dali/devel-api/scripting/scripting.h>
31 #include <dali/integration-api/debug.h>
34 #include <dali-toolkit/public-api/visuals/image-visual-properties.h>
35 #include <dali-toolkit/public-api/visuals/visual-properties.h>
36 #include <dali-toolkit/internal/visuals/texture-manager-impl.h>
37 #include <dali-toolkit/internal/visuals/visual-string-constants.h>
38 #include <dali-toolkit/internal/visuals/visual-factory-impl.h>
39 #include <dali-toolkit/internal/visuals/visual-factory-cache.h>
40 #include <dali-toolkit/internal/visuals/visual-base-impl.h>
41 #include <dali-toolkit/internal/visuals/image-atlas-manager.h>
42 #include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
43 #include <dali-toolkit/internal/visuals/visual-url.h>
58 const char * const IMAGE_FITTING_MODE( "fittingMode" );
59 const char * const IMAGE_SAMPLING_MODE( "samplingMode" );
60 const char * const IMAGE_DESIRED_WIDTH( "desiredWidth" );
61 const char * const IMAGE_DESIRED_HEIGHT( "desiredHeight" );
62 const char * const SYNCHRONOUS_LOADING( "synchronousLoading" );
63 const char * const IMAGE_ATLASING("atlasing");
64 const char * const ALPHA_MASK_URL("alphaMaskUrl");
67 DALI_ENUM_TO_STRING_TABLE_BEGIN( FITTING_MODE )
68 DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::FittingMode, SHRINK_TO_FIT )
69 DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::FittingMode, SCALE_TO_FILL )
70 DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::FittingMode, FIT_WIDTH )
71 DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::FittingMode, FIT_HEIGHT )
72 DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::FittingMode, DEFAULT )
73 DALI_ENUM_TO_STRING_TABLE_END( FITTING_MODE )
76 DALI_ENUM_TO_STRING_TABLE_BEGIN( SAMPLING_MODE )
77 DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::SamplingMode, BOX )
78 DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::SamplingMode, NEAREST )
79 DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::SamplingMode, LINEAR )
80 DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::SamplingMode, BOX_THEN_NEAREST )
81 DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::SamplingMode, BOX_THEN_LINEAR )
82 DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::SamplingMode, NO_FILTER )
83 DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::SamplingMode, DONT_CARE )
84 DALI_ENUM_TO_STRING_TABLE_END( SAMPLING_MODE )
87 DALI_ENUM_TO_STRING_TABLE_BEGIN( WRAP_MODE )
88 DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::WrapMode, DEFAULT )
89 DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::WrapMode, CLAMP_TO_EDGE )
90 DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::WrapMode, REPEAT )
91 DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::WrapMode, MIRRORED_REPEAT )
92 DALI_ENUM_TO_STRING_TABLE_END( WRAP_MODE )
95 DALI_ENUM_TO_STRING_TABLE_BEGIN( RELEASE_POLICY )
96 DALI_ENUM_TO_STRING_WITH_SCOPE( DevelImageVisual::ReleasePolicy, DETACHED )
97 DALI_ENUM_TO_STRING_WITH_SCOPE( DevelImageVisual::ReleasePolicy, DESTROYED )
98 DALI_ENUM_TO_STRING_WITH_SCOPE( DevelImageVisual::ReleasePolicy, NEVER )
99 DALI_ENUM_TO_STRING_TABLE_END( RELEASE_POLICY )
101 const Vector4 FULL_TEXTURE_RECT(0.f, 0.f, 1.f, 1.f);
103 const char* DEFAULT_SAMPLER_TYPENAME = "sampler2D";
105 const float PIXEL_ALIGN_ON = 1.0f;
106 const float PIXEL_ALIGN_OFF = 0.0f;
108 const char* VERTEX_SHADER = DALI_COMPOSE_SHADER(
109 attribute mediump vec2 aPosition;\n
110 uniform mediump mat4 uModelMatrix;\n
111 uniform mediump mat4 uViewMatrix;\n
112 uniform mediump mat4 uProjection;\n
113 uniform mediump vec3 uSize;\n
114 uniform mediump vec4 pixelArea;
115 varying mediump vec2 vTexCoord;\n
116 uniform lowp float uPixelAligned;\n
118 //Visual size and offset
119 uniform mediump vec2 offset;\n
120 uniform mediump vec2 size;\n
121 uniform mediump vec4 offsetSizeMode;\n
122 uniform mediump vec2 origin;\n
123 uniform mediump vec2 anchorPoint;\n
125 vec4 ComputeVertexPosition()\n
127 vec2 visualSize = mix(uSize.xy*size, size, offsetSizeMode.zw );\n
128 vec2 visualOffset = mix( offset, offset/uSize.xy, offsetSizeMode.xy);\n
129 return vec4( (aPosition + anchorPoint)*visualSize + (visualOffset + origin)*uSize.xy, 0.0, 1.0 );\n
134 mediump vec4 vertexPosition = uViewMatrix * uModelMatrix * ComputeVertexPosition();\n
135 vec4 alignedVertexPosition = vertexPosition;\n
136 alignedVertexPosition.xy = floor ( vertexPosition.xy );\n // Pixel alignment
137 vertexPosition = uProjection * mix( vertexPosition, alignedVertexPosition, uPixelAligned );\n
138 vTexCoord = pixelArea.xy+pixelArea.zw*(aPosition + vec2(0.5) );\n
139 gl_Position = vertexPosition;\n
143 const char* FRAGMENT_SHADER_NO_ATLAS = DALI_COMPOSE_SHADER(
144 varying mediump vec2 vTexCoord;\n
145 uniform sampler2D sTexture;\n
146 uniform lowp vec4 uColor;\n
147 uniform lowp vec3 mixColor;\n
148 uniform lowp float opacity;\n
149 uniform lowp float preMultipliedAlpha;\n
151 lowp vec4 visualMixColor()\n
153 return vec4( mixColor * mix( 1.0, opacity, preMultipliedAlpha ), opacity );\n
157 gl_FragColor = texture2D( sTexture, vTexCoord ) * uColor * visualMixColor();\n
161 const char* FRAGMENT_SHADER_ATLAS_CLAMP = DALI_COMPOSE_SHADER(
162 varying mediump vec2 vTexCoord;\n
163 uniform sampler2D sTexture;\n
164 uniform mediump vec4 uAtlasRect;\n
165 uniform lowp vec4 uColor;\n
166 uniform lowp vec3 mixColor;\n
167 uniform lowp float opacity;\n
168 uniform lowp float preMultipliedAlpha;\n
170 lowp vec4 visualMixColor()\n
172 return vec4( mixColor * mix( 1.0, opacity, preMultipliedAlpha ), opacity );\n
177 mediump vec2 texCoord = clamp( mix( uAtlasRect.xy, uAtlasRect.zw, vTexCoord ), uAtlasRect.xy, uAtlasRect.zw );\n
178 gl_FragColor = texture2D( sTexture, texCoord ) * uColor * visualMixColor();\n
182 const char* FRAGMENT_SHADER_ATLAS_VARIOUS_WRAP = DALI_COMPOSE_SHADER(
183 varying mediump vec2 vTexCoord;\n
184 uniform sampler2D sTexture;\n
185 uniform mediump vec4 uAtlasRect;\n
186 // WrapMode -- 0: CLAMP; 1: REPEAT; 2: REFLECT;
187 uniform lowp vec2 wrapMode;\n
188 uniform lowp vec4 uColor;\n
189 uniform lowp vec3 mixColor;\n
190 uniform lowp float opacity;\n
191 uniform lowp float preMultipliedAlpha;\n
193 mediump float wrapCoordinate( mediump vec2 range, mediump float coordinate, lowp float wrap )\n
195 mediump float coord;\n
196 if( wrap > 1.5 )\n // REFLECT
197 coord = 1.0-abs(fract(coordinate*0.5)*2.0 - 1.0);\n
198 else \n// warp == 0 or 1
199 coord = mix(coordinate, fract( coordinate ), wrap);\n
200 return clamp( mix(range.x, range.y, coord), range.x, range.y );
203 lowp vec4 visualMixColor()\n
205 return vec4( mixColor * mix( 1.0, opacity, preMultipliedAlpha ), opacity );\n
210 mediump vec2 texCoord = vec2( wrapCoordinate( uAtlasRect.xz, vTexCoord.x, wrapMode.x ),
211 wrapCoordinate( uAtlasRect.yw, vTexCoord.y, wrapMode.y ) );\n
212 gl_FragColor = texture2D( sTexture, texCoord ) * uColor * visualMixColor();\n
216 Geometry CreateGeometry( VisualFactoryCache& factoryCache, ImageDimensions gridSize )
220 if( gridSize == ImageDimensions( 1, 1 ) )
222 geometry = factoryCache.GetGeometry( VisualFactoryCache::QUAD_GEOMETRY );
226 geometry = VisualFactoryCache::CreateGridGeometry( gridSize );
232 } // unnamed namespace
234 ImageVisualPtr ImageVisual::New( VisualFactoryCache& factoryCache,
235 const VisualUrl& imageUrl,
236 const Property::Map& properties,
237 ImageDimensions size,
238 FittingMode::Type fittingMode,
239 Dali::SamplingMode::Type samplingMode )
241 ImageVisualPtr imageVisualPtr( new ImageVisual( factoryCache, imageUrl, size, fittingMode, samplingMode ) );
242 imageVisualPtr->SetProperties( properties );
243 return imageVisualPtr;
246 ImageVisualPtr ImageVisual::New( VisualFactoryCache& factoryCache,
247 const VisualUrl& imageUrl,
248 ImageDimensions size,
249 FittingMode::Type fittingMode,
250 Dali::SamplingMode::Type samplingMode )
252 return new ImageVisual( factoryCache, imageUrl, size, fittingMode, samplingMode );
255 ImageVisualPtr ImageVisual::New( VisualFactoryCache& factoryCache, const Image& image )
257 return new ImageVisual( factoryCache, image );
260 ImageVisual::ImageVisual( VisualFactoryCache& factoryCache,
261 const VisualUrl& imageUrl,
262 ImageDimensions size,
263 FittingMode::Type fittingMode,
264 Dali::SamplingMode::Type samplingMode )
265 : Visual::Base( factoryCache ),
267 mPixelArea( FULL_TEXTURE_RECT ),
269 mImageUrl( imageUrl ),
271 mDesiredSize( size ),
272 mTextureId( TextureManager::INVALID_TEXTURE_ID ),
273 mFittingMode( fittingMode ),
274 mSamplingMode( samplingMode ),
275 mWrapModeU( WrapMode::DEFAULT ),
276 mWrapModeV( WrapMode::DEFAULT ),
277 mReleasePolicy( DevelImageVisual::ReleasePolicy::DETACHED ),
278 mAttemptAtlasing( false ),
283 ImageVisual::ImageVisual( VisualFactoryCache& factoryCache, const Image& image )
284 : Visual::Base( factoryCache ),
286 mPixelArea( FULL_TEXTURE_RECT ),
291 mTextureId( TextureManager::INVALID_TEXTURE_ID ),
292 mFittingMode( FittingMode::DEFAULT ),
293 mSamplingMode( SamplingMode::DEFAULT ),
294 mWrapModeU( WrapMode::DEFAULT ),
295 mWrapModeV( WrapMode::DEFAULT ),
296 mReleasePolicy( DevelImageVisual::ReleasePolicy::DESTROYED ),
297 mAttemptAtlasing( false ),
302 ImageVisual::~ImageVisual()
304 if( Stage::IsInstalled() )
308 // TextureManager could have been deleted before the actor that contains this
309 // ImageVisual is destroyed (e.g. due to stage shutdown). Ensure the stage
310 // is still valid before accessing texture manager.
311 if( mMaskingData->mAlphaMaskId != TextureManager::INVALID_TEXTURE_ID )
313 TextureManager& textureManager = mFactoryCache.GetTextureManager();
314 textureManager.Remove( mMaskingData->mAlphaMaskId );
318 // ImageVisual destroyed so remove texture unless ReleasePolicy is set to never release
319 if( ( mTextureId != TextureManager::INVALID_TEXTURE_ID ) && ( mReleasePolicy != DevelImageVisual::ReleasePolicy::NEVER ) )
326 void ImageVisual::DoSetProperties( const Property::Map& propertyMap )
328 // Url is already received in constructor
329 for( Property::Map::SizeType iter = 0; iter < propertyMap.Count(); ++iter )
331 KeyValuePair keyValue = propertyMap.GetKeyValue( iter );
332 if( keyValue.first.type == Property::Key::INDEX )
334 DoSetProperty( keyValue.first.indexKey, keyValue.second );
338 if( keyValue.first == IMAGE_FITTING_MODE )
340 DoSetProperty( Toolkit::ImageVisual::Property::FITTING_MODE, keyValue.second );
342 else if( keyValue.first == IMAGE_SAMPLING_MODE )
344 DoSetProperty( Toolkit::ImageVisual::Property::SAMPLING_MODE, keyValue.second );
346 else if( keyValue.first == IMAGE_DESIRED_WIDTH )
348 DoSetProperty( Toolkit::ImageVisual::Property::DESIRED_WIDTH, keyValue.second );
350 else if( keyValue.first == IMAGE_DESIRED_HEIGHT )
352 DoSetProperty( Toolkit::ImageVisual::Property::DESIRED_HEIGHT, keyValue.second );
354 else if( keyValue.first == PIXEL_AREA_UNIFORM_NAME )
356 DoSetProperty( Toolkit::ImageVisual::Property::PIXEL_AREA, keyValue.second );
358 else if( keyValue.first == IMAGE_WRAP_MODE_U )
360 DoSetProperty( Toolkit::ImageVisual::Property::WRAP_MODE_U, keyValue.second );
362 else if( keyValue.first == IMAGE_WRAP_MODE_V )
364 DoSetProperty( Toolkit::ImageVisual::Property::WRAP_MODE_V, keyValue.second );
366 else if( keyValue.first == SYNCHRONOUS_LOADING )
368 DoSetProperty( Toolkit::ImageVisual::Property::SYNCHRONOUS_LOADING, keyValue.second );
370 else if( keyValue.first == IMAGE_ATLASING )
372 DoSetProperty( Toolkit::ImageVisual::Property::ATLASING, keyValue.second );
374 else if( keyValue.first == ALPHA_MASK_URL )
376 DoSetProperty( Toolkit::ImageVisual::Property::ALPHA_MASK_URL, keyValue.second );
378 else if( keyValue.first == MASK_CONTENT_SCALE_NAME )
380 DoSetProperty( Toolkit::ImageVisual::Property::MASK_CONTENT_SCALE, keyValue.second );
382 else if( keyValue.first == CROP_TO_MASK_NAME )
384 DoSetProperty( Toolkit::ImageVisual::Property::CROP_TO_MASK, keyValue.second );
386 else if( keyValue.first == RELEASE_POLICY_NAME )
388 DoSetProperty( Toolkit::DevelImageVisual::Property::RELEASE_POLICY, keyValue.second );
394 void ImageVisual::DoSetProperty( Property::Index index, const Property::Value& value )
398 case Toolkit::ImageVisual::Property::SYNCHRONOUS_LOADING:
401 if( value.Get( sync ) )
405 mImpl->mFlags |= Impl::IS_SYNCHRONOUS_RESOURCE_LOADING;
409 mImpl->mFlags &= ~Impl::IS_SYNCHRONOUS_RESOURCE_LOADING;
414 DALI_LOG_ERROR("ImageVisual: synchronousLoading property has incorrect type\n");
419 case Toolkit::ImageVisual::Property::DESIRED_WIDTH:
422 if( value.Get( desiredWidth ) )
424 mDesiredSize.SetWidth( desiredWidth );
428 DALI_LOG_ERROR("ImageVisual: desiredWidth property has incorrect type\n");
433 case Toolkit::ImageVisual::Property::DESIRED_HEIGHT:
436 if( value.Get( desiredHeight ) )
438 mDesiredSize.SetHeight( desiredHeight );
442 DALI_LOG_ERROR("ImageVisual: desiredHeight property has incorrect type\n");
447 case Toolkit::ImageVisual::Property::FITTING_MODE:
450 Scripting::GetEnumerationProperty( value, FITTING_MODE_TABLE, FITTING_MODE_TABLE_COUNT, fittingMode );
451 mFittingMode = Dali::FittingMode::Type( fittingMode );
455 case Toolkit::ImageVisual::Property::SAMPLING_MODE:
458 Scripting::GetEnumerationProperty( value, SAMPLING_MODE_TABLE, SAMPLING_MODE_TABLE_COUNT, samplingMode );
459 mSamplingMode = Dali::SamplingMode::Type( samplingMode );
463 case Toolkit::ImageVisual::Property::PIXEL_AREA:
465 value.Get( mPixelArea );
469 case Toolkit::ImageVisual::Property::WRAP_MODE_U:
472 Scripting::GetEnumerationProperty( value, WRAP_MODE_TABLE, WRAP_MODE_TABLE_COUNT, wrapMode );
473 mWrapModeU = Dali::WrapMode::Type( wrapMode );
477 case Toolkit::ImageVisual::Property::WRAP_MODE_V:
480 Scripting::GetEnumerationProperty( value, WRAP_MODE_TABLE, WRAP_MODE_TABLE_COUNT, wrapMode );
481 mWrapModeV = Dali::WrapMode::Type( wrapMode );
485 case Toolkit::ImageVisual::Property::ATLASING:
487 bool atlasing = false;
488 mAttemptAtlasing = value.Get( atlasing );
492 case Toolkit::ImageVisual::Property::ALPHA_MASK_URL:
494 std::string alphaUrl;
495 if( value.Get( alphaUrl ) )
498 // Immediately trigger the alpha mask loading (it may just get a cached value)
499 mMaskingData->mAlphaMaskUrl = alphaUrl;
500 TextureManager& textureManager = mFactoryCache.GetTextureManager();
501 mMaskingData->mAlphaMaskId = textureManager.RequestMaskLoad( alphaUrl );
506 case Toolkit::ImageVisual::Property::MASK_CONTENT_SCALE:
509 if( value.Get( scale ) )
512 mMaskingData->mContentScaleFactor = scale;
517 case Toolkit::ImageVisual::Property::CROP_TO_MASK:
520 if( value.Get( crop ) )
523 mMaskingData->mCropToMask = crop;
528 case Toolkit::DevelImageVisual::Property::RELEASE_POLICY:
531 Scripting::GetEnumerationProperty( value, RELEASE_POLICY_TABLE, RELEASE_POLICY_TABLE_COUNT, releasePolicy );
532 mReleasePolicy = DevelImageVisual::ReleasePolicy::Type( releasePolicy );
538 void ImageVisual::AllocateMaskData()
542 mMaskingData.reset(new TextureManager::MaskingData());
546 void ImageVisual::GetNaturalSize( Vector2& naturalSize )
550 naturalSize.x = mImage.GetWidth();
551 naturalSize.y = mImage.GetHeight();
554 else if( mDesiredSize.GetWidth()>0 && mDesiredSize.GetHeight()>0)
556 naturalSize.x = mDesiredSize.GetWidth();
557 naturalSize.y = mDesiredSize.GetHeight();
560 else if( mImpl->mRenderer ) // Check if we have a loaded image
562 auto textureSet = mImpl->mRenderer.GetTextures();
566 auto texture = textureSet.GetTexture(0);
567 naturalSize.x = texture.GetWidth();
568 naturalSize.y = texture.GetHeight();
573 if( mMaskingData != NULL && mMaskingData->mAlphaMaskUrl.IsValid() &&
574 mMaskingData->mCropToMask )
576 ImageDimensions dimensions = Dali::GetClosestImageSize( mMaskingData->mAlphaMaskUrl.GetUrl() );
577 if( dimensions != ImageDimensions( 0, 0 ) )
579 naturalSize.x = dimensions.GetWidth();
580 naturalSize.y = dimensions.GetHeight();
584 else if( mImageUrl.IsValid() )
586 if( mImageUrl.GetProtocolType() == VisualUrl::LOCAL )
588 ImageDimensions dimensions = Dali::GetClosestImageSize( mImageUrl.GetUrl() );
590 if( dimensions != ImageDimensions( 0, 0 ) )
592 naturalSize.x = dimensions.GetWidth();
593 naturalSize.y = dimensions.GetHeight();
597 Image brokenImage = VisualFactoryCache::GetBrokenVisualImage();
599 naturalSize.x = brokenImage.GetWidth();
600 naturalSize.y = brokenImage.GetWidth();
606 naturalSize = Vector2::ZERO;
609 void ImageVisual::CreateRenderer( TextureSet& textureSet )
614 if( !mImpl->mCustomShader )
616 geometry = CreateGeometry( mFactoryCache, ImageDimensions( 1, 1 ) );
618 shader = GetImageShader( mFactoryCache,
619 mImpl->mFlags & Impl::IS_ATLASING_APPLIED,
620 mWrapModeU <= WrapMode::CLAMP_TO_EDGE && mWrapModeV <= WrapMode::CLAMP_TO_EDGE );
624 geometry = CreateGeometry( mFactoryCache, mImpl->mCustomShader->mGridSize );
625 if( mImpl->mCustomShader->mVertexShader.empty() && mImpl->mCustomShader->mFragmentShader.empty() )
627 shader = GetImageShader( mFactoryCache, false, true );
631 shader = Shader::New( mImpl->mCustomShader->mVertexShader.empty() ? VERTEX_SHADER : mImpl->mCustomShader->mVertexShader,
632 mImpl->mCustomShader->mFragmentShader.empty() ? FRAGMENT_SHADER_NO_ATLAS : mImpl->mCustomShader->mFragmentShader,
633 mImpl->mCustomShader->mHints );
634 if( mImpl->mCustomShader->mVertexShader.empty() )
636 shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
641 // Set pixel align off as default.
642 // ToDo: Pixel align causes issues such as rattling image animation.
643 // We should trun it off until issues are resolved
644 shader.RegisterProperty( PIXEL_ALIGNED_UNIFORM_NAME, PIXEL_ALIGN_OFF );
646 mImpl->mRenderer = Renderer::New( geometry, shader );
649 mImpl->mRenderer.SetTextures( textureSet );
651 // else still waiting for texture load to finish.
653 //Register transform properties
654 mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT );
657 void ImageVisual::CreateNativeImageRenderer( NativeImage& nativeImage )
662 std::string fragmentShader;
663 const char* fragmentPreFix = nativeImage.GetCustomFragmentPreFix();
664 const char* customSamplerTypename = nativeImage.GetCustomSamplerTypename();
668 fragmentShader = fragmentPreFix;
669 fragmentShader += "\n";
672 if( mImpl->mCustomShader && !mImpl->mCustomShader->mFragmentShader.empty() )
674 fragmentShader += mImpl->mCustomShader->mFragmentShader;
678 fragmentShader += FRAGMENT_SHADER_NO_ATLAS;
681 if( customSamplerTypename )
683 fragmentShader.replace( fragmentShader.find( DEFAULT_SAMPLER_TYPENAME ), strlen( DEFAULT_SAMPLER_TYPENAME ), customSamplerTypename );
686 if( !mImpl->mCustomShader )
688 geometry = CreateGeometry( mFactoryCache, ImageDimensions( 1, 1 ) );
690 shader = Shader::New( VERTEX_SHADER, fragmentShader );
691 shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
695 geometry = CreateGeometry( mFactoryCache, mImpl->mCustomShader->mGridSize );
696 shader = Shader::New( mImpl->mCustomShader->mVertexShader.empty() ? VERTEX_SHADER : mImpl->mCustomShader->mVertexShader,
698 mImpl->mCustomShader->mHints );
699 if( mImpl->mCustomShader->mVertexShader.empty() )
701 shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
705 mImpl->mRenderer = Renderer::New( geometry, shader );
707 //Register transform properties
708 mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT );
712 bool ImageVisual::IsSynchronousResourceLoading() const
714 return mImpl->mFlags & Impl::IS_SYNCHRONOUS_RESOURCE_LOADING;
718 ( VisualUrl& url, Dali::ImageDimensions desiredSize, Dali::FittingMode::Type fittingMode, Dali::SamplingMode::Type samplingMode,
719 ImageVisual::MaskingData* maskInfo, bool synchronousLoading,
720 TextureManager::TextureId textureId, Vector4& textureRect, bool& atlasingStatus, bool& loadingStatus
722 void ImageVisual::InitializeRenderer()
724 mImpl->mFlags &= ~Impl::IS_ATLASING_APPLIED;
726 TextureManager& textureManager = mFactoryCache.GetTextureManager();
728 if( ! mImpl->mCustomShader && mImageUrl.GetProtocolType() == VisualUrl::LOCAL )
730 bool defaultWrapMode = mWrapModeU <= WrapMode::CLAMP_TO_EDGE && mWrapModeV <= WrapMode::CLAMP_TO_EDGE;
734 auto attemptAtlasing = mAttemptAtlasing;
736 // texture set has to be created first as we need to know if atlasing succeeded or not
737 // when selecting the shader
738 TextureSet textures =
739 textureManager.LoadTexture(mImageUrl, mDesiredSize, mFittingMode, mSamplingMode,
740 mMaskingData, IsSynchronousResourceLoading(), mTextureId,
741 atlasRect, attemptAtlasing, mLoading, mWrapModeU,
742 mWrapModeV, this, this, mFactoryCache.GetAtlasManager());
745 mImpl->mFlags |= Impl::IS_ATLASING_APPLIED;
747 CreateRenderer( textures );
749 if( mImpl->mFlags & Impl::IS_ATLASING_APPLIED ) // the texture is packed inside atlas
751 mImpl->mRenderer.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, atlasRect );
752 if( !defaultWrapMode ) // custom wrap mode
754 Vector2 wrapMode(mWrapModeU-WrapMode::CLAMP_TO_EDGE, mWrapModeV-WrapMode::CLAMP_TO_EDGE);
755 wrapMode.Clamp( Vector2::ZERO, Vector2( 2.f, 2.f ) );
756 mImpl->mRenderer.RegisterProperty( WRAP_MODE_UNIFORM_NAME, wrapMode );
762 auto attemptAtlasing = false;
763 // for custom shader or remote image, atlas is not applied
764 Vector4 atlasRect; // ignored in this case
765 TextureSet textures =
766 textureManager.LoadTexture(mImageUrl, mDesiredSize, mFittingMode, mSamplingMode,
767 mMaskingData, IsSynchronousResourceLoading(), mTextureId,
768 atlasRect, attemptAtlasing, mLoading, mWrapModeU, mWrapModeV, this,
769 nullptr, nullptr); // no atlasing
770 DALI_ASSERT_DEBUG(attemptAtlasing == false);
771 CreateRenderer( textures );
775 void ImageVisual::InitializeRenderer( const Image& image )
777 TextureSet textures = TextureSet::New();
779 NativeImage nativeImage = NativeImage::DownCast( image );
782 CreateNativeImageRenderer( nativeImage );
783 DALI_ASSERT_DEBUG( textures );
784 mImpl->mRenderer.SetTextures( textures );
788 // reuse existing code for regular images
789 CreateRenderer( textures );
791 ApplyImageToSampler( image );
794 void ImageVisual::DoSetOnStage( Actor& actor )
796 if( mImageUrl.IsValid() )
798 InitializeRenderer();
802 InitializeRenderer( mImage );
805 if( !mImpl->mRenderer )
810 mPlacementActor = actor;
811 // Search the Actor tree to find if Layer UI behaviour set.
812 Layer layer = actor.GetLayer();
813 if( layer && layer.GetBehavior() == Layer::LAYER_3D )
815 // Layer 3D set, do not align pixels
816 mImpl->mRenderer.RegisterProperty( PIXEL_ALIGNED_UNIFORM_NAME, PIXEL_ALIGN_OFF );
819 if( mPixelArea != FULL_TEXTURE_RECT )
821 mImpl->mRenderer.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, mPixelArea );
824 if( mLoading == false )
826 actor.AddRenderer( mImpl->mRenderer );
827 mPlacementActor.Reset();
829 // Image loaded and ready to display
834 void ImageVisual::DoSetOffStage( Actor& actor )
836 // Visual::Base::SetOffStage only calls DoSetOffStage if mRenderer exists (is on onstage)
838 // Image release is dependent on the ReleasePolicy, renderer is destroyed.
839 actor.RemoveRenderer( mImpl->mRenderer);
840 if( mReleasePolicy == DevelImageVisual::ReleasePolicy::DETACHED )
842 RemoveTexture(); // If INVALID_TEXTURE_ID then removal will be attempted on atlas
845 if( mImageUrl.IsValid() )
847 // Legacy support for deprecated Dali::Image
851 mImpl->mRenderer.Reset();
852 mPlacementActor.Reset();
855 void ImageVisual::DoCreatePropertyMap( Property::Map& map ) const
858 map.Insert( Toolkit::Visual::Property::TYPE, Toolkit::Visual::IMAGE );
860 bool sync = IsSynchronousResourceLoading();
861 map.Insert( SYNCHRONOUS_LOADING, sync );
862 if( mImageUrl.IsValid() )
864 map.Insert( Toolkit::ImageVisual::Property::URL, mImageUrl.GetUrl() );
865 map.Insert( Toolkit::ImageVisual::Property::DESIRED_WIDTH, mDesiredSize.GetWidth() );
866 map.Insert( Toolkit::ImageVisual::Property::DESIRED_HEIGHT, mDesiredSize.GetHeight() );
870 map.Insert( Toolkit::ImageVisual::Property::DESIRED_WIDTH, static_cast<int>(mImage.GetWidth()) );
871 map.Insert( Toolkit::ImageVisual::Property::DESIRED_HEIGHT, static_cast<int>(mImage.GetHeight()) );
873 ResourceImage resourceImage = ResourceImage::DownCast(mImage);
876 map.Insert( Toolkit::ImageVisual::Property::URL, resourceImage.GetUrl() );
880 map.Insert( Toolkit::ImageVisual::Property::FITTING_MODE, mFittingMode );
881 map.Insert( Toolkit::ImageVisual::Property::SAMPLING_MODE, mSamplingMode );
883 map.Insert( Toolkit::ImageVisual::Property::PIXEL_AREA, mPixelArea );
884 map.Insert( Toolkit::ImageVisual::Property::WRAP_MODE_U, mWrapModeU );
885 map.Insert( Toolkit::ImageVisual::Property::WRAP_MODE_V, mWrapModeV );
887 map.Insert( Toolkit::ImageVisual::Property::ATLASING, mAttemptAtlasing );
888 if( mMaskingData != NULL )
890 map.Insert( Toolkit::ImageVisual::Property::ALPHA_MASK_URL, mMaskingData->mAlphaMaskUrl.GetUrl() );
891 map.Insert( Toolkit::ImageVisual::Property::MASK_CONTENT_SCALE, mMaskingData->mContentScaleFactor );
892 map.Insert( Toolkit::ImageVisual::Property::CROP_TO_MASK, mMaskingData->mCropToMask );
895 map.Insert( Toolkit::DevelImageVisual::Property::RELEASE_POLICY, mReleasePolicy );
899 void ImageVisual::DoCreateInstancePropertyMap( Property::Map& map ) const
902 map.Insert( Toolkit::Visual::Property::TYPE, Toolkit::Visual::IMAGE );
903 if( mImageUrl.IsValid() )
905 map.Insert( Toolkit::ImageVisual::Property::DESIRED_WIDTH, mDesiredSize.GetWidth() );
906 map.Insert( Toolkit::ImageVisual::Property::DESIRED_HEIGHT, mDesiredSize.GetHeight() );
910 map.Insert( Toolkit::ImageVisual::Property::DESIRED_WIDTH, static_cast<int>(mImage.GetWidth()) );
911 map.Insert( Toolkit::ImageVisual::Property::DESIRED_HEIGHT, static_cast<int>(mImage.GetHeight()) );
915 void ImageVisual::OnSetTransform()
917 if( mImpl->mRenderer )
919 mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT );
923 Shader ImageVisual::GetImageShader( VisualFactoryCache& factoryCache, bool atlasing, bool defaultTextureWrapping )
928 if( defaultTextureWrapping )
930 shader = factoryCache.GetShader( VisualFactoryCache::IMAGE_SHADER_ATLAS_DEFAULT_WRAP );
933 shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_ATLAS_CLAMP );
934 shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
935 factoryCache.SaveShader( VisualFactoryCache::IMAGE_SHADER_ATLAS_DEFAULT_WRAP, shader );
940 shader = factoryCache.GetShader( VisualFactoryCache::IMAGE_SHADER_ATLAS_CUSTOM_WRAP );
943 shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_ATLAS_VARIOUS_WRAP );
944 shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
945 factoryCache.SaveShader( VisualFactoryCache::IMAGE_SHADER_ATLAS_CUSTOM_WRAP, shader );
951 shader = factoryCache.GetShader( VisualFactoryCache::IMAGE_SHADER );
954 shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_NO_ATLAS );
955 shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
956 factoryCache.SaveShader( VisualFactoryCache::IMAGE_SHADER, shader );
963 void ImageVisual::ApplyImageToSampler( const Image& image )
967 TextureSet textureSet = mImpl->mRenderer.GetTextures();
968 DALI_ASSERT_DEBUG( textureSet ); // texture set should always exist by this time
970 TextureSetImage( textureSet, 0u, image );
971 Sampler sampler = Sampler::New();
972 sampler.SetWrapMode( mWrapModeU, mWrapModeV );
973 textureSet.SetSampler( 0u, sampler );
977 // From existing atlas manager
978 void ImageVisual::UploadCompleted()
980 // Texture has been uploaded. If weak handle is holding a placement actor, it is the time to add the renderer to actor.
981 Actor actor = mPlacementActor.GetHandle();
984 actor.AddRenderer( mImpl->mRenderer );
986 // reset the weak handle so that the renderer only get added to actor once
987 mPlacementActor.Reset();
992 // From Texture Manager
993 void ImageVisual::UploadComplete( bool loadingSuccess, int32_t textureId, TextureSet textureSet, bool usingAtlas, const Vector4& atlasRectangle )
995 Actor actor = mPlacementActor.GetHandle();
998 if( mImpl->mRenderer )
1000 actor.AddRenderer( mImpl->mRenderer );
1001 // reset the weak handle so that the renderer only get added to actor once
1002 mPlacementActor.Reset();
1004 if( loadingSuccess )
1006 Sampler sampler = Sampler::New();
1007 sampler.SetWrapMode( mWrapModeU, mWrapModeV );
1008 textureSet.SetSampler( 0u, sampler );
1009 mImpl->mRenderer.SetTextures(textureSet);
1013 Image brokenImage = VisualFactoryCache::GetBrokenVisualImage();
1015 textureSet = TextureSet::New();
1016 mImpl->mRenderer.SetTextures( textureSet );
1018 ApplyImageToSampler( brokenImage );
1020 // Image loaded and ready to display
1027 void ImageVisual::RemoveTexture()
1029 if( mTextureId != TextureManager::INVALID_TEXTURE_ID )
1031 mFactoryCache.GetTextureManager().Remove( mTextureId );
1032 mTextureId = TextureManager::INVALID_TEXTURE_ID;
1036 Vector4 atlasRect( 0.f, 0.f, 1.f, 1.f );
1037 Property::Index index = mImpl->mRenderer.GetPropertyIndex( ATLAS_RECT_UNIFORM_NAME );
1038 if( index != Property::INVALID_INDEX )
1040 Property::Value atlasRectValue = mImpl->mRenderer.GetProperty( index );
1041 atlasRectValue.Get( atlasRect );
1044 TextureSet textureSet = mImpl->mRenderer.GetTextures();
1045 mImpl->mRenderer.Reset();
1047 if( index != Property::INVALID_INDEX )
1049 mFactoryCache.GetAtlasManager()->Remove( textureSet, atlasRect );
1054 } // namespace Internal
1056 } // namespace Toolkit