From 3c85db1f136e34adae5c0c3db18b93e01db0b19f Mon Sep 17 00:00:00 2001 From: Kimmo Hoikka Date: Fri, 15 Sep 2017 17:57:01 +0100 Subject: [PATCH] Add support for Imagevisual to use External Texture as input through Url Change-Id: I36ddb93fb33569ec40f317b3c763845a59cd2c10 --- .../src/dali-toolkit/utc-Dali-ImageView.cpp | 26 ++- dali-toolkit/devel-api/file.list | 3 +- .../internal/visuals/image/image-visual.cpp | 186 ++++++--------------- dali-toolkit/internal/visuals/image/image-visual.h | 18 +- .../internal/visuals/texture-manager-impl.cpp | 134 ++++++++++++++- .../internal/visuals/texture-manager-impl.h | 41 +++-- 6 files changed, 230 insertions(+), 178 deletions(-) diff --git a/automated-tests/src/dali-toolkit/utc-Dali-ImageView.cpp b/automated-tests/src/dali-toolkit/utc-Dali-ImageView.cpp index 31909d9..bac289e 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-ImageView.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-ImageView.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -589,7 +590,6 @@ int UtcDaliImageViewSyncLoading(void) END_TEST; } - int UtcDaliImageViewSyncLoading02(void) { ToolkitTestApplication application; @@ -626,6 +626,30 @@ int UtcDaliImageViewSyncLoading02(void) END_TEST; } +int UtcDaliImageViewAddedTexture(void) +{ + ToolkitTestApplication application; + + tet_infoline("ImageView Testing image view with texture provided manager url"); + + ImageView imageView = ImageView::New(); + + // empty texture is ok, though pointless from app point of view + TextureSet empty; + std::string url = TextureManager::AddTexture(empty); + DALI_TEST_CHECK(url.size() > 0u); + + Property::Map propertyMap; + propertyMap[ImageVisual::Property::URL] = url; + imageView.SetProperty(ImageView::Property::IMAGE, propertyMap); + + Stage::GetCurrent().Add( imageView ); + application.SendNotification(); + application.Render(); + + END_TEST; +} + int UtcDaliImageViewSizeWithBackground(void) { ToolkitTestApplication application; diff --git a/dali-toolkit/devel-api/file.list b/dali-toolkit/devel-api/file.list index 5cf6797..85275d9 100644 --- a/dali-toolkit/devel-api/file.list +++ b/dali-toolkit/devel-api/file.list @@ -117,7 +117,8 @@ devel_api_focus_manager_header_files = \ devel_api_image_loader_header_files = \ $(devel_api_src_dir)/image-loader/async-image-loader-devel.h \ $(devel_api_src_dir)/image-loader/atlas-upload-observer.h \ - $(devel_api_src_dir)/image-loader/image-atlas.h + $(devel_api_src_dir)/image-loader/image-atlas.h \ + $(devel_api_src_dir)/image-loader/texture-manager.h devel_api_scripting_header_files = \ $(devel_api_src_dir)/scripting/script.h \ diff --git a/dali-toolkit/internal/visuals/image/image-visual.cpp b/dali-toolkit/internal/visuals/image/image-visual.cpp index ab956e8..8961b4b 100644 --- a/dali-toolkit/internal/visuals/image/image-visual.cpp +++ b/dali-toolkit/internal/visuals/image/image-visual.cpp @@ -269,7 +269,7 @@ ImageVisual::ImageVisual( VisualFactoryCache& factoryCache, mWrapModeU( WrapMode::DEFAULT ), mWrapModeV( WrapMode::DEFAULT ), mAttemptAtlasing( false ), - mTextureLoading( false ) + mLoadingStatus( false ) { } @@ -287,12 +287,23 @@ ImageVisual::ImageVisual( VisualFactoryCache& factoryCache, const Image& image ) mWrapModeU( WrapMode::DEFAULT ), mWrapModeV( WrapMode::DEFAULT ), mAttemptAtlasing( false ), - mTextureLoading( false ) + mLoadingStatus( false ) { } ImageVisual::~ImageVisual() { + if( mMaskingData && Stage::IsInstalled() ) + { + // TextureManager could have been deleted before the actor that contains this + // ImageVisual is destroyed (e.g. due to stage shutdown). Ensure the stage + // is still valid before accessing texture manager. + if( mMaskingData->mAlphaMaskId != TextureManager::INVALID_TEXTURE_ID ) + { + TextureManager& textureManager = mFactoryCache.GetTextureManager(); + textureManager.Remove( mMaskingData->mAlphaMaskId ); + } + } delete mMaskingData; } @@ -358,7 +369,6 @@ void ImageVisual::DoSetProperties( const Property::Map& propertyMap ) } } } - } void ImageVisual::DoSetProperty( Property::Index index, const Property::Value& value ) @@ -466,7 +476,9 @@ void ImageVisual::DoSetProperty( Property::Index index, const Property::Value& v { AllocateMaskData(); // Immediately trigger the alpha mask loading (it may just get a cached value) - mMaskingData->SetImage( alphaUrl ); + mMaskingData->mAlphaMaskUrl = alphaUrl; + TextureManager& textureManager = mFactoryCache.GetTextureManager(); + mMaskingData->mAlphaMaskId = textureManager.RequestMaskLoad( alphaUrl ); } break; } @@ -499,8 +511,7 @@ void ImageVisual::AllocateMaskData() { if( mMaskingData == NULL ) { - TextureManager& textureManager = mFactoryCache.GetTextureManager(); - mMaskingData = new MaskingData(textureManager); + mMaskingData = new TextureManager::MaskingData(); } } @@ -675,118 +686,42 @@ bool ImageVisual::IsSynchronousResourceLoading() const return mImpl->mFlags & Impl::IS_SYNCHRONOUS_RESOURCE_LOADING; } -TextureSet ImageVisual::CreateTextureSet( Vector4& textureRect, bool synchronousLoading, bool attemptAtlasing ) -{ - TextureSet textureSet; - - mTextureLoading = false; - textureRect = FULL_TEXTURE_RECT; - - if( synchronousLoading ) - { - PixelData data; - if( mImageUrl.IsValid() ) - { - // if sync loading is required, the loading should immediately when actor is on stage - Devel::PixelBuffer pixelBuffer = LoadImageFromFile( mImageUrl.GetUrl(), mDesiredSize, mFittingMode, mSamplingMode ); - - if( pixelBuffer ) - { - data = Devel::PixelBuffer::Convert(pixelBuffer); // takes ownership of buffer - } - } - if( !data ) - { - // use broken image - textureSet = TextureSet::New(); - TextureSetImage( textureSet, 0u, VisualFactoryCache::GetBrokenVisualImage() ); - } - else - { - if( attemptAtlasing ) - { - textureSet = mFactoryCache.GetAtlasManager()->Add( textureRect, data ); - mImpl->mFlags |= Impl::IS_ATLASING_APPLIED; - } - if( !textureSet ) // big image, no atlasing or atlasing failed - { - mImpl->mFlags &= ~Impl::IS_ATLASING_APPLIED; - Texture texture = Texture::New( Dali::TextureType::TEXTURE_2D, data.GetPixelFormat(), - data.GetWidth(), data.GetHeight() ); - texture.Upload( data ); - textureSet = TextureSet::New(); - textureSet.SetTexture( 0u, texture ); - } - } - } - else - { - mTextureLoading = true; - if( attemptAtlasing ) - { - textureSet = mFactoryCache.GetAtlasManager()->Add( textureRect, mImageUrl.GetUrl(), mDesiredSize, mFittingMode, true, this ); - mImpl->mFlags |= Impl::IS_ATLASING_APPLIED; - } - if( !textureSet ) // big image, no atlasing or atlasing failed - { - mImpl->mFlags &= ~Impl::IS_ATLASING_APPLIED; - TextureManager& textureManager = mFactoryCache.GetTextureManager(); - if( mMaskingData == NULL ) - { - mTextureId = textureManager.RequestLoad( mImageUrl, mDesiredSize, mFittingMode, - mSamplingMode, TextureManager::NO_ATLAS, this ); - } - else - { - mTextureId = textureManager.RequestLoad( mImageUrl, - mMaskingData->mAlphaMaskId, - mMaskingData->mContentScaleFactor, - mDesiredSize, - mFittingMode, mSamplingMode, - TextureManager::NO_ATLAS, - mMaskingData->mCropToMask, - this ); - } - - TextureManager::LoadState loadState = textureManager.GetTextureState( mTextureId ); - mTextureLoading = ( loadState == TextureManager::LOADING ); - - if( loadState == TextureManager::UPLOADED ) - { - // UploadComplete has already been called - keep the same texture set - textureSet = textureManager.GetTextureSet(mTextureId); - } - } - } - - if( ! (mImpl->mFlags & Impl::IS_ATLASING_APPLIED) && textureSet ) - { - Sampler sampler = Sampler::New(); - sampler.SetWrapMode( mWrapModeU, mWrapModeV ); - textureSet.SetSampler( 0u, sampler ); - } - - return textureSet; -} - +/* +( VisualUrl& url, Dali::ImageDimensions desiredSize, Dali::FittingMode::Type fittingMode, Dali::SamplingMode::Type samplingMode, + ImageVisual::MaskingData* maskInfo, bool synchronousLoading, + TextureManager::TextureId textureId, Vector4& textureRect, bool& atlasingStatus, bool& loadingStatus + */ void ImageVisual::InitializeRenderer() { mImpl->mFlags &= ~Impl::IS_ATLASING_APPLIED; + TextureManager& textureManager = mFactoryCache.GetTextureManager(); + if( ! mImpl->mCustomShader && mImageUrl.GetProtocolType() == VisualUrl::LOCAL ) { bool defaultWrapMode = mWrapModeU <= WrapMode::CLAMP_TO_EDGE && mWrapModeV <= WrapMode::CLAMP_TO_EDGE; Vector4 atlasRect; + + auto attemptAtlasing = mAttemptAtlasing; + // texture set has to be created first as we need to know if atlasing succeeded or not // when selecting the shader - TextureSet textures = CreateTextureSet( atlasRect, IsSynchronousResourceLoading(), mAttemptAtlasing ); + TextureSet textures = + textureManager.LoadTexture(mImageUrl, mDesiredSize, mFittingMode, mSamplingMode, + mMaskingData, IsSynchronousResourceLoading(), mTextureId, + atlasRect, attemptAtlasing, mLoadingStatus, mWrapModeU, + mWrapModeV, this, this, mFactoryCache.GetAtlasManager()); + if(attemptAtlasing) + { + mImpl->mFlags |= Impl::IS_ATLASING_APPLIED; + } CreateRenderer( textures ); if( mImpl->mFlags & Impl::IS_ATLASING_APPLIED ) // the texture is packed inside atlas { mImpl->mRenderer.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, atlasRect ); - if( !defaultWrapMode ) // custom wrap mode, renderer is not cached. + if( !defaultWrapMode ) // custom wrap mode { Vector2 wrapMode(mWrapModeU-WrapMode::CLAMP_TO_EDGE, mWrapModeV-WrapMode::CLAMP_TO_EDGE); wrapMode.Clamp( Vector2::ZERO, Vector2( 2.f, 2.f ) ); @@ -796,16 +731,21 @@ void ImageVisual::InitializeRenderer() } else { + auto attemptAtlasing = false; // for custom shader or remote image, atlas is not applied Vector4 atlasRect; // ignored in this case - TextureSet textures = CreateTextureSet( atlasRect, IsSynchronousResourceLoading(), false ); + TextureSet textures = + textureManager.LoadTexture(mImageUrl, mDesiredSize, mFittingMode, mSamplingMode, + mMaskingData, IsSynchronousResourceLoading(), mTextureId, + atlasRect, attemptAtlasing, mLoadingStatus, mWrapModeU, mWrapModeV, this, + nullptr, nullptr); // no atlasing + DALI_ASSERT_DEBUG(attemptAtlasing == false); CreateRenderer( textures ); } } void ImageVisual::InitializeRenderer( const Image& image ) { - // don't reuse CreateTextureSet TextureSet textures = TextureSet::New(); NativeImage nativeImage = NativeImage::DownCast( image ); @@ -853,7 +793,7 @@ void ImageVisual::DoSetOnStage( Actor& actor ) mImpl->mRenderer.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, mPixelArea ); } - if( mTextureLoading == false ) + if( mLoadingStatus == false ) { actor.AddRenderer( mImpl->mRenderer ); mPlacementActor.Reset(); @@ -874,7 +814,7 @@ void ImageVisual::DoSetOffStage( Actor& actor ) RemoveTexture( mImageUrl.GetUrl() ); mImage.Reset(); } - mTextureLoading = false; + mLoadingStatus = false; mImpl->mRenderer.Reset(); mPlacementActor.Reset(); } @@ -1010,7 +950,7 @@ void ImageVisual::UploadCompleted() // reset the weak handle so that the renderer only get added to actor once mPlacementActor.Reset(); } - mTextureLoading = false; + mLoadingStatus = false; } // From Texture Manager @@ -1045,7 +985,7 @@ void ImageVisual::UploadComplete( bool loadingSuccess, int32_t textureId, Textur ResourceReady(); } } - mTextureLoading = false; + mLoadingStatus = false; } void ImageVisual::RemoveTexture(const std::string& url) @@ -1075,36 +1015,6 @@ void ImageVisual::RemoveTexture(const std::string& url) } } - -ImageVisual::MaskingData::MaskingData( TextureManager& textureManager ) -: mTextureManager( textureManager ), - mAlphaMaskUrl(), - mAlphaMaskId( TextureManager::INVALID_TEXTURE_ID ), - mContentScaleFactor( 1.0f ), - mCropToMask( true ) -{ -} - -ImageVisual::MaskingData::~MaskingData() -{ - if( Stage::IsInstalled() ) - { - // TextureManager could have been deleted before the actor that contains this - // ImageVisual is destroyed (e.g. due to stage shutdown). Ensure the stage - // is still valid before accessing texture manager. - if( mAlphaMaskId != TextureManager::INVALID_TEXTURE_ID ) - { - mTextureManager.Remove( mAlphaMaskId ); - } - } -} - -void ImageVisual::MaskingData::SetImage( const std::string& maskUrl ) -{ - mAlphaMaskUrl = maskUrl; - mAlphaMaskId = mTextureManager.RequestMaskLoad( mAlphaMaskUrl ); -} - } // namespace Internal } // namespace Toolkit diff --git a/dali-toolkit/internal/visuals/image/image-visual.h b/dali-toolkit/internal/visuals/image/image-visual.h index 0c2f756..bee6067 100644 --- a/dali-toolkit/internal/visuals/image/image-visual.h +++ b/dali-toolkit/internal/visuals/image/image-visual.h @@ -314,24 +314,12 @@ private: void DoSetProperty( Property::Index index, const Property::Value& value ); private: - struct MaskingData - { - MaskingData( TextureManager& textureManager ); - ~MaskingData(); - void SetImage( const std::string& url ); - - TextureManager& mTextureManager; - VisualUrl mAlphaMaskUrl; - TextureManager::TextureId mAlphaMaskId; - float mContentScaleFactor; - bool mCropToMask; - }; Image mImage; Vector4 mPixelArea; WeakHandle mPlacementActor; VisualUrl mImageUrl; - MaskingData* mMaskingData; + TextureManager::MaskingData* mMaskingData; Dali::ImageDimensions mDesiredSize; TextureManager::TextureId mTextureId; @@ -340,8 +328,8 @@ private: Dali::SamplingMode::Type mSamplingMode:4; Dali::WrapMode::Type mWrapModeU:3; Dali::WrapMode::Type mWrapModeV:3; - bool mAttemptAtlasing:1; ///< If true will attempt atlasing, otherwise create unique texture - bool mTextureLoading:1; ///< True if the texture is being loaded asynchronously, or false when it has loaded. + bool mAttemptAtlasing; ///< If true will attempt atlasing, otherwise create unique texture + bool mLoadingStatus; ///< True if the texture is being loaded asynchronously, or false when it has loaded. }; diff --git a/dali-toolkit/internal/visuals/texture-manager-impl.cpp b/dali-toolkit/internal/visuals/texture-manager-impl.cpp index f074087..66f6a81 100644 --- a/dali-toolkit/internal/visuals/texture-manager-impl.cpp +++ b/dali-toolkit/internal/visuals/texture-manager-impl.cpp @@ -21,7 +21,9 @@ // EXTERNAL HEADERS #include #include +#include #include +#include #include #include #include @@ -30,6 +32,7 @@ // INTERNAL HEADERS #include #include +#include namespace { @@ -84,6 +87,13 @@ const int INVALID_CACHE_INDEX( -1 ); ///< Invalid Cache index } // Anonymous namespace +TextureManager::MaskingData::MaskingData() +: mAlphaMaskUrl(), + mAlphaMaskId( INVALID_TEXTURE_ID ), + mContentScaleFactor( 1.0f ), + mCropToMask( true ) +{ +} TextureManager::TextureManager() : mAsyncLocalLoaders( GetNumberOfLocalLoaderThreads(), [&]() { return AsyncLoadingHelper(*this); } ), @@ -92,6 +102,125 @@ TextureManager::TextureManager() { } +TextureSet TextureManager::LoadTexture( + VisualUrl& url, Dali::ImageDimensions desiredSize, Dali::FittingMode::Type fittingMode, + Dali::SamplingMode::Type samplingMode, const MaskingDataPointer& maskInfo, + bool synchronousLoading, TextureManager::TextureId& textureId, Vector4& textureRect, + bool& atlasingStatus, bool& loadingStatus, Dali::WrapMode::Type wrapModeU, + Dali::WrapMode::Type wrapModeV, TextureUploadObserver* textureObserver, + AtlasUploadObserver* atlasObserver, ImageAtlasManagerPtr imageAtlasManager) +{ + TextureSet textureSet; + + loadingStatus = false; + textureRect = FULL_ATLAS_RECT; + + if( VisualUrl::TEXTURE == url.GetProtocolType()) + { + std::string location = url.GetLocation(); + if( location.size() > 0u ) + { + TextureId id = std::stoi( location ); + for( auto&& elem : mExternalTextures ) + { + if( elem.textureId == id ) + { + return elem.textureSet; + } + } + } + } + else if( synchronousLoading ) + { + PixelData data; + if( url.IsValid() ) + { + // if sync loading is required, the loading should immediately when actor is on stage + Devel::PixelBuffer pixelBuffer = LoadImageFromFile( url.GetUrl(), desiredSize, fittingMode, samplingMode ); + if( pixelBuffer ) + { + data = Devel::PixelBuffer::Convert(pixelBuffer); // takes ownership of buffer + } + } + if( !data ) + { + // use broken image + textureSet = TextureSet::New(); + Devel::PixelBuffer pixelBuffer = LoadImageFromFile( BROKEN_IMAGE_URL ); + if( pixelBuffer ) + { + data = Devel::PixelBuffer::Convert(pixelBuffer); // takes ownership of buffer + } + Texture texture = Texture::New( Dali::TextureType::TEXTURE_2D, data.GetPixelFormat(), + data.GetWidth(), data.GetHeight() ); + texture.Upload( data ); + textureSet = TextureSet::New(); + textureSet.SetTexture( 0u, texture ); + } + else + { + if( atlasingStatus ) // attempt atlasing + { + textureSet = imageAtlasManager->Add( textureRect, data ); + } + if( !textureSet ) // big image, no atlasing or atlasing failed + { + atlasingStatus = false; + Texture texture = Texture::New( Dali::TextureType::TEXTURE_2D, data.GetPixelFormat(), + data.GetWidth(), data.GetHeight() ); + texture.Upload( data ); + textureSet = TextureSet::New(); + textureSet.SetTexture( 0u, texture ); + } + } + } + else + { + loadingStatus = true; + if( atlasingStatus ) + { + textureSet = imageAtlasManager->Add( textureRect, url.GetUrl(), desiredSize, fittingMode, true, atlasObserver ); + } + if( !textureSet ) // big image, no atlasing or atlasing failed + { + atlasingStatus = false; + if( !maskInfo ) + { + textureId = RequestLoad( url, desiredSize, fittingMode, samplingMode, TextureManager::NO_ATLAS, textureObserver ); + } + else + { + textureId = RequestLoad( url, + maskInfo->mAlphaMaskId, + maskInfo->mContentScaleFactor, + desiredSize, + fittingMode, samplingMode, + TextureManager::NO_ATLAS, + maskInfo->mCropToMask, + textureObserver ); + } + + TextureManager::LoadState loadState = GetTextureState( textureId ); + loadingStatus = ( loadState == TextureManager::LOADING ); + + if( loadState == TextureManager::UPLOADED ) + { + // UploadComplete has already been called - keep the same texture set + textureSet = GetTextureSet( textureId ); + } + } + } + + if( ! atlasingStatus && textureSet ) + { + Sampler sampler = Sampler::New(); + sampler.SetWrapMode( wrapModeU, wrapModeV ); + textureSet.SetSampler( 0u, sampler ); + } + + return textureSet; +} + TextureManager::TextureId TextureManager::RequestLoad( const VisualUrl& url, const ImageDimensions desiredSize, @@ -123,7 +252,6 @@ TextureManager::TextureId TextureManager::RequestMaskLoad( const VisualUrl& mask return RequestLoadInternal( maskUrl, INVALID_TEXTURE_ID, 1.0f, ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::NO_FILTER, NO_ATLAS, false, KEEP_PIXEL_BUFFER, NULL ); } - TextureManager::TextureId TextureManager::RequestLoadInternal( const VisualUrl& url, TextureId maskTextureId, @@ -715,10 +843,6 @@ void TextureManager::ObserverDestroyed( TextureUploadObserver* observer ) } } -TextureManager::~TextureManager() -{ -} - TextureManager::AsyncLoadingHelper::AsyncLoadingHelper(TextureManager& textureManager) : AsyncLoadingHelper(Toolkit::AsyncImageLoader::New(), textureManager, AsyncLoadingInfoContainerType()) diff --git a/dali-toolkit/internal/visuals/texture-manager-impl.h b/dali-toolkit/internal/visuals/texture-manager-impl.h index 117bd1f..868afdc 100644 --- a/dali-toolkit/internal/visuals/texture-manager-impl.h +++ b/dali-toolkit/internal/visuals/texture-manager-impl.h @@ -45,6 +45,8 @@ namespace Toolkit namespace Internal { +class ImageAtlasManager; +typedef IntrusivePtr ImageAtlasManagerPtr; /** * The TextureManager provides a common Image loading API for Visuals. @@ -103,6 +105,17 @@ public: public: + struct MaskingData + { + MaskingData(); + ~MaskingData() = default; + + VisualUrl mAlphaMaskUrl; + TextureManager::TextureId mAlphaMaskId; + float mContentScaleFactor; + bool mCropToMask; + }; + /** * Constructor. */ @@ -111,11 +124,20 @@ public: /** * Destructor. */ - ~TextureManager(); + ~TextureManager() = default; // TextureManager Main API: + TextureSet LoadTexture(VisualUrl& url, Dali::ImageDimensions desiredSize, + Dali::FittingMode::Type fittingMode, Dali::SamplingMode::Type samplingMode, + MaskingData* maskInfo, bool synchronousLoading, + TextureManager::TextureId& textureId, Vector4& textureRect, + bool& atlasingStatus, bool& loadingStatus, Dali::WrapMode::Type wrapModeU, + Dali::WrapMode::Type wrapModeV, TextureUploadObserver* textureObserver, + AtlasUploadObserver* atlasObserver, + ImageAtlasManagerPtr imageAtlasManager); + /** * @brief Requests an image load of the given URL. * @@ -345,25 +367,9 @@ private: unsigned short loadId; ///< The load Id used by the async loader to reference this load }; - /** - * @brief This struct is used within a container to manage atlas creation and destruction. - */ - struct AtlasInfo - { - AtlasInfo( Toolkit::ImageAtlas atlas, TextureSet textureSet ) - : atlas( atlas ), - textureSet( textureSet ) - { - } - - Toolkit::ImageAtlas atlas; ///< The ImageAtlas object - TextureSet textureSet; ///< The TextureSet is kept in the struct to allow fast lookup of TextureSet to Atlas - }; - // Private typedefs: typedef std::deque AsyncLoadingInfoContainerType; ///< The container type used to manage Asynchronous loads in progress - typedef std::vector AtlasInfoContainerType; ///< The container type used to manage Atlas creation and destruction typedef std::vector TextureInfoContainerType; ///< The container type used to manage the life-cycle and caching of Textures /** @@ -586,7 +592,6 @@ private: private: // Member Variables: - AtlasInfoContainerType mAtlasContainer; ///< Used to manage Atlas creation and destruction TextureInfoContainerType mTextureInfoContainer; ///< Used to manage the life-cycle and caching of Textures RoundRobinContainerView< AsyncLoadingHelper > mAsyncLocalLoaders; ///< The Asynchronous image loaders used to provide all local async loads RoundRobinContainerView< AsyncLoadingHelper > mAsyncRemoteLoaders; ///< The Asynchronous image loaders used to provide all remote async loads -- 2.7.4