utc-Dali-FlexContainer.cpp
utc-Dali-GaussianBlurView.cpp
utc-Dali-ImageView.cpp
+ utc-Dali-ImageVisual.cpp
utc-Dali-JsonParser.cpp
utc-Dali-KeyInputFocusManager.cpp
utc-Dali-PageTurnView.cpp
#include <climits>
#include <cstdio>
#include <unistd.h>
-
-namespace Dali
-{
+#include <vector>
+#include <algorithm>
namespace
{
-EventThreadCallback* gEventThreadCallback = NULL;
+// Note, this is not thread safe - however, should not be using
+// triggers from multiple threads - they should all be created on
+// event thread.
+std::vector<Dali::EventThreadCallback*> gEventThreadCallbacks;
}
+
+namespace Dali
+{
+
struct EventThreadCallback::Impl
{
CallbackBase* callback;
- unsigned int triggeredCount;
- unsigned int expectedCount;
sem_t mySemaphore;
};
: mImpl( new Impl() )
{
mImpl->callback = callback;
- mImpl->triggeredCount = 0u;
- mImpl->expectedCount = UINT_MAX;
sem_init( &(mImpl->mySemaphore), 0, 0 );
- gEventThreadCallback = this;
+
+ gEventThreadCallbacks.push_back(this);
}
EventThreadCallback::~EventThreadCallback()
{
+ std::vector<EventThreadCallback*>::iterator iter =
+ std::find(gEventThreadCallbacks.begin(), gEventThreadCallbacks.end(), this);
+ if( iter != gEventThreadCallbacks.end() )
+ {
+ gEventThreadCallbacks.erase(iter);
+ }
delete mImpl;
}
void EventThreadCallback::Trigger()
{
- mImpl->triggeredCount++;
- if( mImpl->triggeredCount >= mImpl->expectedCount )
- {
- sem_post( &(mImpl->mySemaphore) );
- }
+ sem_post( &(mImpl->mySemaphore) );
}
-bool EventThreadCallback::WaitingForTrigger(unsigned int count, unsigned int seconds)
+// returns true if timed out rather than triggered
+bool EventThreadCallback::WaitingForTrigger()
{
- if( mImpl->triggeredCount >= count )
- {
- return true;
- }
struct timespec now;
clock_gettime( CLOCK_REALTIME, &now );
- now.tv_sec += seconds;
- mImpl->expectedCount = count;
+ if( now.tv_nsec < 999900000 ) // 999, 900, 000
+ now.tv_nsec += 100000;
+ else
+ {
+ now.tv_sec += 1;
+ now.tv_nsec = 0;
+ }
+
int error = sem_timedwait( &(mImpl->mySemaphore), &now );
- return error != 0;
+ return error != 0; // true if timeout
}
CallbackBase* EventThreadCallback::GetCallback()
return mImpl->callback;
}
-EventThreadCallback* EventThreadCallback::Get()
-{
- return gEventThreadCallback;
}
-}
namespace Test
{
bool WaitForEventThreadTrigger( int triggerCount )
{
- bool success = true;
const int TEST_TIMEOUT(30);
struct timespec startTime;
now.tv_sec = startTime.tv_sec;
now.tv_nsec = startTime.tv_nsec;
- Dali::EventThreadCallback* eventTrigger = NULL;
- while( eventTrigger == NULL )
+ // Round robin poll of each semaphore:
+ while ( triggerCount > 0 )
{
- eventTrigger = Dali::EventThreadCallback::Get();
+ if( gEventThreadCallbacks.size() > 0 )
+ {
+ for( std::vector<Dali::EventThreadCallback*>::iterator iter = gEventThreadCallbacks.begin();
+ iter != gEventThreadCallbacks.end(); ++iter )
+ {
+ Dali::EventThreadCallback* eventTrigger = (*iter);
+ Dali::CallbackBase* callback = eventTrigger->GetCallback();
+ bool timedout = eventTrigger->WaitingForTrigger();
+ if( ! timedout )
+ {
+ // Semaphore was unlocked - execute the trigger
+ Dali::CallbackBase::Execute( *callback );
+ triggerCount--;
+ }
+ }
+ }
clock_gettime( CLOCK_REALTIME, &now );
if( now.tv_sec - startTime.tv_sec > TEST_TIMEOUT )
{
- success = false;
+ // Ensure we break out of the loop if elapsed time has passed
break;
}
- usleep(10);
- }
- if( eventTrigger != NULL )
- {
- Dali::CallbackBase* callback = eventTrigger->GetCallback();
- eventTrigger->WaitingForTrigger( triggerCount, TEST_TIMEOUT - (now.tv_sec - startTime.tv_sec) );
- Dali::CallbackBase::Execute( *callback );
}
clock_gettime( CLOCK_REALTIME, &now );
{
fprintf(stderr, "WaitForEventThreadTrigger took %ld seconds\n", now.tv_sec - startTime.tv_sec );
}
- return success;
+ return triggerCount == 0;
}
}
void Trigger();
- bool WaitingForTrigger(unsigned int count, unsigned int seconds );
+ bool WaitingForTrigger();
CallbackBase* GetCallback();
- static EventThreadCallback* Get();
-
private:
// undefined copy constructor.
application.GetPlatform().SetClosestImageSize( Vector2(100, 100) );
Stage::GetCurrent().Add( imageView3 );
- DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 3 ), true, TEST_LOCATION );
+ DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
application.SendNotification();
application.Render(RENDER_FRAME_INTERVAL);
--- /dev/null
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <iostream>
+#include <stdlib.h>
+#include <dali-toolkit-test-suite-utils.h>
+#include <toolkit-timer.h>
+#include <toolkit-bitmap-loader.h>
+#include <toolkit-event-thread-callback.h>
+#include <dali/public-api/rendering/renderer.h>
+#include <dali/public-api/rendering/texture-set.h>
+#include <dali/public-api/rendering/shader.h>
+#include <dali/devel-api/images/nine-patch-image.h>
+#include <dali/devel-api/object/handle-devel.h>
+#include <dali-toolkit/devel-api/align-enums.h>
+#include <dali-toolkit/devel-api/visuals/visual-properties-devel.h>
+#include <dali-toolkit/devel-api/visuals/image-visual-properties-devel.h>
+#include <dali-toolkit/devel-api/visual-factory/transition-data.h>
+#include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include "dummy-control.h"
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+
+void dali_image_visual_startup(void)
+{
+ test_return_value = TET_UNDEF;
+}
+
+void dali_image_visual_cleanup(void)
+{
+ test_return_value = TET_PASS;
+}
+
+namespace
+{
+const char* TEST_IMAGE_FILE_NAME = TEST_RESOURCE_DIR "/gallery_small-1.jpg";
+const char* TEST_LARGE_IMAGE_FILE_NAME = TEST_RESOURCE_DIR "/tbcol.png";
+const char* TEST_SMALL_IMAGE_FILE_NAME = TEST_RESOURCE_DIR "/icon-edit.png";
+const char* TEST_REMOTE_IMAGE_FILE_NAME = "https://www.tizen.org/sites/all/themes/tizen_theme/logo.png";
+}
+
+
+Actor CreateActorWithImageVisual(const Property::Map& map)
+{
+ VisualFactory factory = VisualFactory::Get();
+ DummyControl actor = DummyControl::New();
+ DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+ Visual::Base visual = factory.CreateVisual( map );
+ DALI_TEST_CHECK( visual );
+ dummyImpl.RegisterVisual( Control::CONTROL_PROPERTY_END_INDEX + 1, visual );
+ actor.SetSize( 200.f, 200.f );
+ DALI_TEST_EQUALS( actor.GetRendererCount(), 0u, TEST_LOCATION );
+ return actor;
+}
+
+void TestVisualRender( ToolkitTestApplication& application,
+ DummyControl& actor,
+ Visual::Base& visual,
+ std::size_t expectedSamplers = 0,
+ ImageDimensions imageDimensions = ImageDimensions(),
+ Integration::ResourcePointer resourcePtr = Integration::ResourcePointer())
+{
+ DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+ dummyImpl.RegisterVisual( Control::CONTROL_PROPERTY_END_INDEX + 1, visual );
+
+ if( resourcePtr )
+ {
+ // set the image size, for test case, this needs to be set before loading started
+ application.GetPlatform().SetClosestImageSize( Vector2(imageDimensions.GetWidth(), imageDimensions.GetHeight()) );
+ }
+
+ actor.SetSize( 200.f, 200.f );
+ DALI_TEST_EQUALS( actor.GetRendererCount(), 0u, TEST_LOCATION );
+
+ Stage::GetCurrent().Add( actor );
+
+ application.SendNotification(); // Send messages to update
+ application.Render(); // process update and render
+ application.SendNotification(); // process any signals to event
+
+ if( resourcePtr )
+ {
+ DALI_TEST_EQUALS( application.GetPlatform().WasCalled(TestPlatformAbstraction::LoadResourceSynchronouslyFunc ), true, TEST_LOCATION);
+ }
+
+ DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION );
+}
+
+static void TestMixColor( Visual::Base visual, Property::Index mixColorIndex, const Vector4& testColor )
+{
+ Property::Map map;
+ visual.CreatePropertyMap(map);
+ Property::Value* value = map.Find( mixColorIndex );
+ DALI_TEST_CHECK( value );
+ Vector3 mixColor1;
+ DALI_TEST_CHECK( value->Get( mixColor1 ) );
+ DALI_TEST_EQUALS( mixColor1, Vector3(testColor), 0.001, TEST_LOCATION );
+
+ value = map.Find( DevelVisual::Property::MIX_COLOR );
+ DALI_TEST_CHECK( value );
+ Vector4 mixColor2;
+ DALI_TEST_CHECK( value->Get( mixColor2 ) );
+ DALI_TEST_EQUALS( mixColor2, testColor, 0.001, TEST_LOCATION );
+
+ value = map.Find( DevelVisual::Property::OPACITY );
+ DALI_TEST_CHECK( value );
+ float opacity;
+ DALI_TEST_CHECK( value->Get( opacity ) );
+ DALI_TEST_EQUALS( opacity, testColor.a, 0.001, TEST_LOCATION );
+}
+
+
+
+int UtcDaliImageVisualPropertyMap(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline( "Request image visual with a Property::Map" );
+
+ VisualFactory factory = VisualFactory::Get();
+ DALI_TEST_CHECK( factory );
+
+ Property::Map propertyMap;
+ propertyMap.Insert( Visual::Property::TYPE, Visual::IMAGE );
+ propertyMap.Insert( ImageVisual::Property::URL, TEST_LARGE_IMAGE_FILE_NAME );
+
+ Visual::Base visual = factory.CreateVisual( propertyMap );
+ DALI_TEST_CHECK( visual );
+
+ // For tesing the LoadResourceFunc is called, a big image size should be set, so the atlasing is not applied.
+ // Image with a size smaller than 512*512 will be uploaded as a part of the atlas.
+
+ TestGlAbstraction& gl = application.GetGlAbstraction();
+ TraceCallStack& textureTrace = gl.GetTextureTrace();
+ textureTrace.Enable(true);
+
+ DummyControl actor = DummyControl::New();
+ DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+ dummyImpl.RegisterVisual( Control::CONTROL_PROPERTY_END_INDEX + 1, visual );
+
+ actor.SetSize( 200.f, 200.f );
+ DALI_TEST_EQUALS( actor.GetRendererCount(), 0u, TEST_LOCATION );
+
+ Stage::GetCurrent().Add( actor );
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION );
+
+ DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
+
+ Stage::GetCurrent().Remove( actor );
+ DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+
+ END_TEST;
+}
+
+
+int UtcDaliImageVisualRemoteImageLoad(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline( "Request remote image visual with a Property::Map" );
+
+ VisualFactory factory = VisualFactory::Get();
+ DALI_TEST_CHECK( factory );
+
+ Property::Map propertyMap;
+ propertyMap.Insert( Visual::Property::TYPE, Visual::IMAGE );
+ propertyMap.Insert( ImageVisual::Property::URL, TEST_REMOTE_IMAGE_FILE_NAME );
+
+ Visual::Base visual = factory.CreateVisual( propertyMap );
+ DALI_TEST_CHECK( visual );
+
+ TestGlAbstraction& gl = application.GetGlAbstraction();
+ TraceCallStack& textureTrace = gl.GetTextureTrace();
+ textureTrace.Enable(true);
+
+ DummyControl actor = DummyControl::New();
+ DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+ dummyImpl.RegisterVisual( Control::CONTROL_PROPERTY_END_INDEX + 1, visual );
+
+ actor.SetSize( 200.f, 200.f );
+ DALI_TEST_EQUALS( actor.GetRendererCount(), 0u, TEST_LOCATION );
+
+ Stage::GetCurrent().Add( actor );
+ application.SendNotification();
+
+ DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION );
+ DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
+
+ Stage::GetCurrent().Remove( actor );
+ DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+
+ END_TEST;
+}
+
+int UtcDaliImageVisualTextureReuse1(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline( "Request remote image visual with a Property::Map; request a second visual with the same property map - should reuse texture" );
+
+ Property::Map propertyMap;
+ propertyMap.Insert( Visual::Property::TYPE, Visual::IMAGE );
+ propertyMap.Insert( ImageVisual::Property::URL, TEST_LARGE_IMAGE_FILE_NAME );
+
+ TestGlAbstraction& gl = application.GetGlAbstraction();
+ TraceCallStack& textureTrace = gl.GetTextureTrace();
+ textureTrace.Enable(true);
+ TraceCallStack& drawTrace = gl.GetDrawTrace();
+ drawTrace.Enable(true);
+
+ Actor actor = CreateActorWithImageVisual( propertyMap );
+ Stage::GetCurrent().Add( actor );
+ application.SendNotification();
+
+ // Wait for image to load
+ DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION );
+ DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), true, TEST_LOCATION );
+ DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
+ DALI_TEST_EQUALS( drawTrace.FindMethod("DrawArrays"), true, TEST_LOCATION );
+ textureTrace.Reset();
+ drawTrace.Reset();
+
+ Actor actor2 = CreateActorWithImageVisual( propertyMap );
+ Stage::GetCurrent().Add(actor2);
+
+ application.SendNotification(); // Send messages to update
+ application.Render(); // process update and render
+ application.SendNotification(); // process any signals to event
+
+ DALI_TEST_EQUALS( actor2.GetRendererCount(), 1u, TEST_LOCATION );
+
+ tet_infoline("Test that 2 draw calls occur with no new texture gens/binds, i.e. both\n"
+ "draw calls use the same texture as the previous draw call\n" );
+
+ DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), false, TEST_LOCATION );
+ DALI_TEST_EQUALS( drawTrace.CountMethod("DrawArrays"), 2, TEST_LOCATION );
+ DALI_TEST_EQUALS( textureTrace.CountMethod("BindTexture"), 0, TEST_LOCATION );
+
+ tet_infoline("Test that removing 1 actor doesn't delete the texture\n");
+
+ Stage::GetCurrent().Remove( actor );
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+ DALI_TEST_EQUALS( textureTrace.CountMethod("DeleteTextures"), 0, TEST_LOCATION );
+
+ tet_infoline("Test that removing last actor does delete the texture\n");
+
+ Stage::GetCurrent().Remove( actor2 );
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_CHECK( actor2.GetRendererCount() == 0u );
+ DALI_TEST_EQUALS( textureTrace.CountMethod("DeleteTextures"), 1, TEST_LOCATION );
+
+ END_TEST;
+}
+
+
+int UtcDaliImageVisualTextureReuse2(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline( "Request remote image visual with a Property::Map; request a second visual with the same url but different property map - should create new texture" );
+
+ Property::Map propertyMap;
+ propertyMap.Insert( Visual::Property::TYPE, Visual::IMAGE );
+ propertyMap.Insert( ImageVisual::Property::URL, TEST_REMOTE_IMAGE_FILE_NAME );
+
+ TestGlAbstraction& gl = application.GetGlAbstraction();
+ TraceCallStack& textureTrace = gl.GetTextureTrace();
+ textureTrace.Enable(true);
+ TraceCallStack& drawTrace = gl.GetDrawTrace();
+ drawTrace.Enable(true);
+
+ Actor actor = CreateActorWithImageVisual( propertyMap );
+ Stage::GetCurrent().Add( actor );
+ application.SendNotification();
+
+ // Wait for image to load
+ DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION );
+ DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), true, TEST_LOCATION );
+ DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
+ DALI_TEST_EQUALS( drawTrace.FindMethod("DrawArrays"), true, TEST_LOCATION );
+ textureTrace.Reset();
+ drawTrace.Reset();
+
+ propertyMap.Insert( ImageVisual::Property::SAMPLING_MODE, Dali::SamplingMode::NEAREST );
+ propertyMap.Insert( ImageVisual::Property::DESIRED_WIDTH, 100 );
+ propertyMap.Insert( ImageVisual::Property::DESIRED_HEIGHT, 100 );
+ Actor actor2 = CreateActorWithImageVisual( propertyMap );
+ Stage::GetCurrent().Add(actor2);
+
+ application.SendNotification();
+
+ // Wait for image to load
+ DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS( actor2.GetRendererCount(), 1u, TEST_LOCATION );
+
+ tet_infoline("Test that 2 draw calls occur with 1 new texture gen/bind, i.e. both "
+ "renderers are using different textures\n" );
+
+ DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), true, TEST_LOCATION );
+ DALI_TEST_EQUALS( drawTrace.CountMethod("DrawArrays"), 2, TEST_LOCATION );
+ DALI_TEST_EQUALS( textureTrace.CountMethod("BindTexture"), 2, TEST_LOCATION );
+
+ tet_infoline("Test that removing 1 actor deletes it's texture\n");
+
+ Stage::GetCurrent().Remove( actor );
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+ DALI_TEST_EQUALS( textureTrace.CountMethod("DeleteTextures"), 1, TEST_LOCATION );
+
+ tet_infoline("Test that removing last actor deletes it's texture\n");
+
+ Stage::GetCurrent().Remove( actor2 );
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_CHECK( actor2.GetRendererCount() == 0u );
+ DALI_TEST_EQUALS( textureTrace.CountMethod("DeleteTextures"), 2, TEST_LOCATION );
+
+ END_TEST;
+}
+
+
+int UtcDaliImageVisualImageHandle(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline( "Request image visual with an image handle" );
+
+ VisualFactory factory = VisualFactory::Get();
+ DALI_TEST_CHECK( factory );
+
+ Image image = ResourceImage::New(TEST_IMAGE_FILE_NAME);
+ Visual::Base visual = factory.CreateVisual( image );
+
+ // For tesing the LoadResourceFunc is called, a big image size should be set, so the atlasing is not applied.
+ // Image with a size smaller than 512*512 will be uploaded as a part of the atlas.
+
+ const int width=512;
+ const int height=513;
+
+ Integration::Bitmap* bitmap = Integration::Bitmap::New( Integration::Bitmap::BITMAP_2D_PACKED_PIXELS, ResourcePolicy::OWNED_DISCARD );
+ bitmap->GetPackedPixelsProfile()->ReserveBuffer( Pixel::RGBA8888, width, height,width, height );
+
+ TestGlAbstraction& gl = application.GetGlAbstraction();
+ TraceCallStack& textureTrace = gl.GetTextureTrace();
+ textureTrace.Enable(true);
+
+ DummyControl actor = DummyControl::New();
+ TestVisualRender( application, actor, visual, 1u,
+ ImageDimensions(width, height),
+ Integration::ResourcePointer(bitmap) );
+
+ DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
+ END_TEST;
+}
+
+int UtcDaliImageVisualCustomWrapModePixelArea(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline( "Request image visual with a Property::Map, test custom wrap mode and pixel area with atlasing" );
+
+ VisualFactory factory = VisualFactory::Get();
+ DALI_TEST_CHECK( factory );
+
+ // Test wrap mode with atlasing. Image with a size smaller than 512*512 will be uploaded as a part of the atlas.
+ const int width=34;
+ const int height=34;
+ const Vector4 pixelArea(-0.5f, -0.5f, 2.f, 2.f);
+
+ Property::Map propertyMap;
+ propertyMap.Insert( Visual::Property::TYPE, Visual::IMAGE );
+ propertyMap.Insert( ImageVisual::Property::URL, TEST_SMALL_IMAGE_FILE_NAME );
+ propertyMap.Insert( ImageVisual::Property::DESIRED_WIDTH, width );
+ propertyMap.Insert( ImageVisual::Property::DESIRED_HEIGHT, height );
+ propertyMap.Insert( ImageVisual::Property::SYNCHRONOUS_LOADING, true );
+ propertyMap.Insert( ImageVisual::Property::PIXEL_AREA, pixelArea );
+ propertyMap.Insert( ImageVisual::Property::WRAP_MODE_U, WrapMode::MIRRORED_REPEAT );
+ propertyMap.Insert( ImageVisual::Property::WRAP_MODE_V, WrapMode::REPEAT );
+ propertyMap.Insert( DevelImageVisual::Property::ATLASING, true );
+
+ Visual::Base visual = factory.CreateVisual( propertyMap );
+ DALI_TEST_CHECK( visual );
+
+ TestGlAbstraction& gl = application.GetGlAbstraction();
+ TraceCallStack& textureTrace = gl.GetTextureTrace();
+ textureTrace.Enable(true);
+ TraceCallStack& texParameterTrace = gl.GetTexParameterTrace();
+ texParameterTrace.Enable( true );
+
+ DummyControl actor = DummyControl::New();
+ DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+ dummyImpl.RegisterVisual( Control::CONTROL_PROPERTY_END_INDEX + 1, visual );
+ actor.SetSize(2000, 2000);
+ actor.SetParentOrigin(ParentOrigin::CENTER);
+ Stage::GetCurrent().Add( actor );
+
+ // loading started
+ application.SendNotification();
+ application.Render();
+
+ BitmapLoader loader = BitmapLoader::GetLatestCreated();
+ DALI_TEST_CHECK( loader );
+ loader.WaitForLoading();// waiting until the image to be loaded
+ DALI_TEST_CHECK( loader.IsLoaded() );
+
+ DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
+
+ DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
+
+ // WITH atlasing, the wrapping is handled manually in shader, so the following gl function should not be called
+ std::stringstream out;
+ out << GL_TEXTURE_2D << ", " << GL_TEXTURE_WRAP_S << ", " << GL_MIRRORED_REPEAT;
+ DALI_TEST_CHECK( !texParameterTrace.FindMethodAndParams("TexParameteri", out.str()) );
+ out.str("");
+ out << GL_TEXTURE_2D << ", " << GL_TEXTURE_WRAP_T << ", " << GL_REPEAT;
+ DALI_TEST_CHECK( !texParameterTrace.FindMethodAndParams("TexParameteri", out.str()) );
+
+ // test the uniforms which used to handle the wrap mode
+ Renderer renderer = actor.GetRendererAt( 0u );
+ DALI_TEST_CHECK( renderer );
+
+ Property::Value pixelAreaValue = renderer.GetProperty( renderer.GetPropertyIndex( "pixelArea" ) );
+ DALI_TEST_EQUALS( pixelAreaValue.Get<Vector4>(), pixelArea, TEST_LOCATION );
+ Vector4 pixelAreaUniform;
+ DALI_TEST_CHECK( gl.GetUniformValue<Vector4>( "pixelArea", pixelAreaUniform ) );
+ DALI_TEST_EQUALS( pixelArea, pixelAreaUniform, Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
+ Property::Value wrapModeValue = renderer.GetProperty( renderer.GetPropertyIndex( "wrapMode" ) );
+ Vector2 wrapMode( WrapMode::MIRRORED_REPEAT-1, WrapMode::REPEAT-1 );
+ DALI_TEST_EQUALS( wrapModeValue.Get<Vector2>(), wrapMode, TEST_LOCATION );
+ Vector2 wrapModeUniform;
+ DALI_TEST_CHECK( gl.GetUniformValue<Vector2>( "wrapMode", wrapModeUniform ) );
+ DALI_TEST_EQUALS( wrapMode, wrapModeUniform, Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
+ actor.Unparent( );
+ DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+
+ END_TEST;
+}
+
+int UtcDaliImageVisualCustomWrapModeNoAtlas(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline( "Request image visual with a Property::Map, test custom wrap mode and pixel area without atlasing" );
+
+ VisualFactory factory = VisualFactory::Get();
+ DALI_TEST_CHECK( factory );
+
+ // Test wrap mode without atlasing. Image with a size bigger than 512*512 will NOT be uploaded as a part of the atlas.
+ const int width=600;
+ const int height=600;
+ const Vector4 pixelArea(-0.5f, -0.5f, 2.f, 2.f);
+
+ Property::Map propertyMap;
+ propertyMap.Insert( Visual::Property::TYPE, Visual::IMAGE );
+ propertyMap.Insert( ImageVisual::Property::URL, TEST_LARGE_IMAGE_FILE_NAME );
+ propertyMap.Insert( ImageVisual::Property::DESIRED_WIDTH, width );
+ propertyMap.Insert( ImageVisual::Property::DESIRED_HEIGHT, height );
+ propertyMap.Insert( ImageVisual::Property::SYNCHRONOUS_LOADING, true );
+ propertyMap.Insert( ImageVisual::Property::PIXEL_AREA, pixelArea );
+ propertyMap.Insert( ImageVisual::Property::WRAP_MODE_U, WrapMode::MIRRORED_REPEAT );
+ propertyMap.Insert( ImageVisual::Property::WRAP_MODE_V, WrapMode::REPEAT );
+
+ Visual::Base visual = factory.CreateVisual( propertyMap );
+ DALI_TEST_CHECK( visual );
+
+ TestGlAbstraction& gl = application.GetGlAbstraction();
+ TraceCallStack& textureTrace = gl.GetTextureTrace();
+ textureTrace.Enable(true);
+ TraceCallStack& texParameterTrace = gl.GetTexParameterTrace();
+ texParameterTrace.Enable( true );
+
+ DummyControl actor = DummyControl::New();
+ DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+ dummyImpl.RegisterVisual( Control::CONTROL_PROPERTY_END_INDEX + 1, visual );
+ actor.SetSize(2000, 2000);
+ actor.SetParentOrigin(ParentOrigin::CENTER);
+ Stage::GetCurrent().Add( actor );
+
+ // loading started
+ application.SendNotification();
+ application.Render();
+
+ BitmapLoader loader = BitmapLoader::GetLatestCreated();
+ DALI_TEST_CHECK( loader );
+ loader.WaitForLoading();// waiting until the image to be loaded
+ DALI_TEST_CHECK( loader.IsLoaded() );
+
+ DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
+
+ DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
+
+ // WITHOUT atlasing, the wrapping is handled by setting gl texture parameters
+ std::stringstream out;
+ out << GL_TEXTURE_2D << ", " << GL_TEXTURE_WRAP_S << ", " << GL_MIRRORED_REPEAT;
+ DALI_TEST_CHECK( texParameterTrace.FindMethodAndParams("TexParameteri", out.str()) );
+ out.str("");
+ out << GL_TEXTURE_2D << ", " << GL_TEXTURE_WRAP_T << ", " << GL_REPEAT;
+ DALI_TEST_CHECK( texParameterTrace.FindMethodAndParams("TexParameteri", out.str()) );
+
+ // test the uniforms which used to handle the wrap mode
+ Renderer renderer = actor.GetRendererAt( 0u );
+ DALI_TEST_CHECK( renderer );
+
+ Property::Value pixelAreaValue = renderer.GetProperty( renderer.GetPropertyIndex( "pixelArea" ) );
+ DALI_TEST_EQUALS( pixelAreaValue.Get<Vector4>(), pixelArea, TEST_LOCATION );
+ Vector4 pixelAreaUniform;
+ DALI_TEST_CHECK( gl.GetUniformValue<Vector4>( "pixelArea", pixelAreaUniform ) );
+ DALI_TEST_EQUALS( pixelArea, pixelAreaUniform, Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
+ Property::Index wrapModeIndex = renderer.GetPropertyIndex( "wrapMode" );
+ DALI_TEST_CHECK(wrapModeIndex == Property::INVALID_INDEX);
+
+ actor.Unparent();
+ DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+
+ END_TEST;
+}
+
+int UtcDaliImageVisualAnimateMixColor(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline( "Animate mix color" );
+
+ application.GetPlatform().SetClosestImageSize( Vector2(100, 100) );
+
+ VisualFactory factory = VisualFactory::Get();
+ Property::Map propertyMap;
+ propertyMap.Insert(Visual::Property::TYPE, Visual::IMAGE);
+ propertyMap.Insert(ImageVisual::Property::URL, TEST_IMAGE_FILE_NAME );
+ propertyMap.Insert("mixColor", Color::BLUE);
+ propertyMap.Insert(ImageVisual::Property::SYNCHRONOUS_LOADING, true);
+ Visual::Base visual = factory.CreateVisual( propertyMap );
+
+ DummyControl actor = DummyControl::New(true);
+ Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(actor.GetImplementation());
+ dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+ actor.SetSize(2000, 2000);
+ actor.SetParentOrigin(ParentOrigin::CENTER);
+ actor.SetColor(Color::BLACK);
+ Stage::GetCurrent().Add(actor);
+
+ DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION);
+
+ Renderer renderer = actor.GetRendererAt(0);
+ Property::Index index = DevelHandle::GetPropertyIndex( renderer, DevelVisual::Property::MIX_COLOR );
+ Property::Value blendModeValue = renderer.GetProperty( Renderer::Property::BLEND_MODE );
+ DALI_TEST_EQUALS( blendModeValue.Get<int>(), (int)BlendMode::AUTO, TEST_LOCATION );
+
+ tet_infoline("Test that the renderer has the mixColor property");
+ DALI_TEST_CHECK( index != Property::INVALID_INDEX );
+
+ const Vector4 TARGET_MIX_COLOR( 1.0f, 0.0f, 0.0f, 0.5f );
+
+ Property::Map map;
+ map["target"] = "testVisual";
+ map["property"] = "mixColor";
+ map["initialValue"] = Color::MAGENTA;
+ map["targetValue"] = TARGET_MIX_COLOR;
+ map["animator"] = Property::Map()
+ .Add("alphaFunction", "LINEAR")
+ .Add("timePeriod", Property::Map()
+ .Add("delay", 0.0f)
+ .Add("duration", 4.0f));
+
+ Dali::Toolkit::TransitionData transition = TransitionData::New( map );
+
+ Animation animation = dummyImpl.CreateTransition( transition );
+
+ blendModeValue = renderer.GetProperty( Renderer::Property::BLEND_MODE );
+ DALI_TEST_EQUALS( blendModeValue.Get<int>(), (int)BlendMode::ON, TEST_LOCATION );
+
+ animation.AnimateTo( Property(actor, Actor::Property::COLOR), Color::WHITE );
+ animation.Play();
+
+ application.SendNotification();
+ application.Render(0); // Ensure animation starts
+ application.Render(2000u); // Halfway point
+ Vector4 testColor(1.0f, 0.0f, 0.5f, 0.75f );
+
+ DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue<Vector4>("uColor", Vector4(0.5f, 0.5f, 0.5f, 1.0f )), true, TEST_LOCATION );
+ DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue<Vector3>("mixColor", Vector3(testColor)), true, TEST_LOCATION );
+ DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue<float>("opacity", testColor.a), true, TEST_LOCATION );
+
+ application.Render(2000u); // Halfway point between blue and white
+
+ DALI_TEST_EQUALS( actor.GetCurrentColor(), Color::WHITE, TEST_LOCATION );
+ DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue<Vector4>("uColor", Color::WHITE ), true, TEST_LOCATION );
+ DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue<Vector3>("mixColor", Vector3(TARGET_MIX_COLOR)), true, TEST_LOCATION );
+ DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue<float>("opacity", TARGET_MIX_COLOR.a), true, TEST_LOCATION );
+
+ TestMixColor( visual, DevelVisual::Property::MIX_COLOR, TARGET_MIX_COLOR );
+
+ blendModeValue = renderer.GetProperty( Renderer::Property::BLEND_MODE );
+ DALI_TEST_EQUALS( blendModeValue.Get<int>(), (int)BlendMode::ON, TEST_LOCATION );
+
+ END_TEST;
+}
+
+int UtcDaliImageVisualAnimateOpacity(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline( "Animate image visual opacity" );
+
+ application.GetPlatform().SetClosestImageSize( Vector2(100, 100) );
+
+ VisualFactory factory = VisualFactory::Get();
+ Property::Map propertyMap;
+ propertyMap.Insert(Visual::Property::TYPE, Visual::IMAGE);
+ propertyMap.Insert(ImageVisual::Property::URL, TEST_IMAGE_FILE_NAME );
+ propertyMap.Insert("opacity", 0.5f);
+ propertyMap.Insert(ImageVisual::Property::SYNCHRONOUS_LOADING, true);
+ Visual::Base visual = factory.CreateVisual( propertyMap );
+
+ DummyControl actor = DummyControl::New(true);
+ Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(actor.GetImplementation());
+ dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+ actor.SetSize(2000, 2000);
+ actor.SetParentOrigin(ParentOrigin::CENTER);
+ actor.SetColor(Color::BLACK);
+ Stage::GetCurrent().Add(actor);
+
+ DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION);
+
+ Renderer renderer = actor.GetRendererAt(0);
+ tet_infoline("Test that the renderer has the opacity property");
+ Property::Index index = DevelHandle::GetPropertyIndex( renderer, DevelVisual::Property::OPACITY );
+ DALI_TEST_CHECK( index != Property::INVALID_INDEX );
+
+
+ Property::Value blendModeValue = renderer.GetProperty( Renderer::Property::BLEND_MODE );
+ DALI_TEST_EQUALS( blendModeValue.Get<int>(), (int)BlendMode::ON, TEST_LOCATION );
+
+ {
+ tet_infoline( "Test that the opacity can be increased to full via animation, and that the blend mode is set appropriately at the start and end of the animation." );
+
+ Property::Map map;
+ map["target"] = "testVisual";
+ map["property"] = "opacity";
+ map["targetValue"] = 1.0f;
+ map["animator"] = Property::Map()
+ .Add("alphaFunction", "LINEAR")
+ .Add("timePeriod", Property::Map()
+ .Add("delay", 0.0f)
+ .Add("duration", 4.0f));
+
+ Dali::Toolkit::TransitionData transition = TransitionData::New( map );
+ Animation animation = dummyImpl.CreateTransition( transition );
+ animation.Play();
+
+ application.SendNotification();
+ application.Render(0); // Ensure animation starts
+ application.Render(2000u); // Halfway point through animation
+ application.SendNotification(); // Handle any signals
+
+ DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue<float>("opacity", 0.75f), true, TEST_LOCATION );
+
+ application.Render(2001u); // end
+ application.SendNotification(); // ensure animation finished signal is sent
+
+ DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue<float>("opacity", 1.0f), true, TEST_LOCATION );
+
+ blendModeValue = renderer.GetProperty( Renderer::Property::BLEND_MODE );
+ DALI_TEST_EQUALS( blendModeValue.Get<int>(), (int)BlendMode::AUTO, TEST_LOCATION );
+ }
+
+
+ {
+ tet_infoline( "Test that the opacity can be reduced via animation, and that the blend mode is set appropriately at the start and end of the animation." );
+
+ Property::Map map;
+ map["target"] = "testVisual";
+ map["property"] = DevelVisual::Property::OPACITY;
+ map["targetValue"] = 0.1f;
+ map["animator"] = Property::Map()
+ .Add("alphaFunction", "LINEAR")
+ .Add("timePeriod", Property::Map()
+ .Add("delay", 0.0f)
+ .Add("duration", 4.0f));
+
+ Dali::Toolkit::TransitionData transition = TransitionData::New( map );
+ Animation animation = dummyImpl.CreateTransition( transition );
+ animation.Play();
+
+ blendModeValue = renderer.GetProperty( Renderer::Property::BLEND_MODE );
+ DALI_TEST_EQUALS( blendModeValue.Get<int>(), (int)BlendMode::ON, TEST_LOCATION );
+
+ application.SendNotification();
+ application.Render(0); // Ensure animation starts
+ application.Render(2000u); // Halfway point
+ application.SendNotification();
+
+ DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue<float>("opacity", 0.55f), true, TEST_LOCATION );
+
+ application.Render(2016u); // end
+ application.SendNotification();
+
+ DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue<float>("opacity", 0.1f), true, TEST_LOCATION );
+
+ blendModeValue = renderer.GetProperty( Renderer::Property::BLEND_MODE );
+ DALI_TEST_EQUALS( blendModeValue.Get<int>(), (int)BlendMode::ON, TEST_LOCATION );
+ }
+
+
+ END_TEST;
+}
+
+int UtcDaliImageVisualAnimatePixelArea(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline( "ImageVisual animate pixel area" );
+
+ application.GetPlatform().SetClosestImageSize( Vector2(100, 100) );
+
+ VisualFactory factory = VisualFactory::Get();
+ Property::Map propertyMap;
+ propertyMap.Insert(Visual::Property::TYPE, Visual::IMAGE);
+ propertyMap.Insert(ImageVisual::Property::URL, TEST_IMAGE_FILE_NAME );
+ propertyMap.Insert("mixColor", Color::BLUE);
+ propertyMap.Insert(ImageVisual::Property::SYNCHRONOUS_LOADING, true);
+ Visual::Base visual = factory.CreateVisual( propertyMap );
+
+ DummyControl actor = DummyControl::New(true);
+ Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(actor.GetImplementation());
+ dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+ actor.SetSize(2000, 2000);
+ actor.SetParentOrigin(ParentOrigin::CENTER);
+ actor.SetColor(Color::BLACK);
+ Stage::GetCurrent().Add(actor);
+
+ DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION);
+
+ Renderer renderer = actor.GetRendererAt(0);
+ Property::Index index = DevelHandle::GetPropertyIndex( renderer, DevelVisual::Property::MIX_COLOR );
+
+ tet_infoline("Test that the renderer has the mixColor property");
+ DALI_TEST_CHECK( index != Property::INVALID_INDEX );
+
+ // TransitionData only takes string keys
+ Property::Map map;
+ map["target"] = "testVisual";
+ map["property"] = "pixelArea";
+ map["initialValue"] = Vector4( 0,0,0,1 );
+ map["targetValue"] = Vector4( 0,0,1,1 ); // Animate width from zero to full
+ map["animator"] = Property::Map()
+ .Add("alphaFunction", "LINEAR")
+ .Add("timePeriod", Property::Map()
+ .Add("delay", 0.0f)
+ .Add("duration", 4.0f));
+
+ Dali::Toolkit::TransitionData transition = TransitionData::New( map );
+
+ Animation animation = dummyImpl.CreateTransition( transition );
+ animation.AnimateTo( Property(actor, Actor::Property::COLOR), Color::WHITE );
+ animation.Play();
+
+ application.SendNotification();
+ application.Render(0); // Ensure animation starts
+ application.Render(2000u); // Halfway point
+
+ DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue<Vector4>("pixelArea", Vector4(0.0f, 0.0f, 0.5f, 1.0f )), true, TEST_LOCATION );
+
+ application.Render(2000u); // End of animation
+
+ DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue<Vector4>("pixelArea", Vector4( 0.0f, 0.0f, 1.0f, 1.0f )), true, TEST_LOCATION );
+
+ END_TEST;
+}
+
+int UtcDaliImageVisualTextureCancelRemoteLoad(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline( "Request remote image visual, then destroy visual to cancel load" );
+
+ Property::Map propertyMap;
+ propertyMap.Insert( Visual::Property::TYPE, Visual::IMAGE );
+ propertyMap.Insert( ImageVisual::Property::URL, TEST_REMOTE_IMAGE_FILE_NAME );
+
+ TestGlAbstraction& gl = application.GetGlAbstraction();
+ TraceCallStack& textureTrace = gl.GetTextureTrace();
+ textureTrace.Enable(true);
+ TraceCallStack& drawTrace = gl.GetDrawTrace();
+ drawTrace.Enable(true);
+
+ Actor actor = CreateActorWithImageVisual( propertyMap );
+ Stage::GetCurrent().Add( actor );
+ application.SendNotification();
+
+ Stage::GetCurrent().Remove( actor );
+ application.SendNotification();
+
+ DALI_TEST_EQUALS( actor.GetRendererCount(), 0u, TEST_LOCATION );
+ DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), false, TEST_LOCATION );
+ DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), false, TEST_LOCATION );
+ DALI_TEST_EQUALS( drawTrace.FindMethod("DrawArrays"), false, TEST_LOCATION );
+
+ END_TEST;
+}
END_TEST;
}
-int UtcDaliVisualAnimateImageVisualMixColor(void)
-{
- ToolkitTestApplication application;
- tet_infoline( "UtcDaliAnimateImageVisual mix color" );
-
- application.GetPlatform().SetClosestImageSize( Vector2(100, 100) );
-
- VisualFactory factory = VisualFactory::Get();
- Property::Map propertyMap;
- propertyMap.Insert(Visual::Property::TYPE, Visual::IMAGE);
- propertyMap.Insert(ImageVisual::Property::URL, TEST_IMAGE_FILE_NAME );
- propertyMap.Insert("mixColor", Color::BLUE);
- propertyMap.Insert(ImageVisual::Property::SYNCHRONOUS_LOADING, true);
- Visual::Base visual = factory.CreateVisual( propertyMap );
-
- DummyControl actor = DummyControl::New(true);
- Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(actor.GetImplementation());
- dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
-
- actor.SetSize(2000, 2000);
- actor.SetParentOrigin(ParentOrigin::CENTER);
- actor.SetColor(Color::BLACK);
- Stage::GetCurrent().Add(actor);
-
- DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION);
-
- Renderer renderer = actor.GetRendererAt(0);
- Property::Index index = DevelHandle::GetPropertyIndex( renderer, DevelVisual::Property::MIX_COLOR );
- Property::Value blendModeValue = renderer.GetProperty( Renderer::Property::BLEND_MODE );
- DALI_TEST_EQUALS( blendModeValue.Get<int>(), (int)BlendMode::AUTO, TEST_LOCATION );
-
- tet_infoline("Test that the renderer has the mixColor property");
- DALI_TEST_CHECK( index != Property::INVALID_INDEX );
-
- const Vector4 TARGET_MIX_COLOR( 1.0f, 0.0f, 0.0f, 0.5f );
-
- Property::Map map;
- map["target"] = "testVisual";
- map["property"] = "mixColor";
- map["initialValue"] = Color::MAGENTA;
- map["targetValue"] = TARGET_MIX_COLOR;
- map["animator"] = Property::Map()
- .Add("alphaFunction", "LINEAR")
- .Add("timePeriod", Property::Map()
- .Add("delay", 0.0f)
- .Add("duration", 4.0f));
-
- Dali::Toolkit::TransitionData transition = TransitionData::New( map );
-
- Animation animation = dummyImpl.CreateTransition( transition );
-
- blendModeValue = renderer.GetProperty( Renderer::Property::BLEND_MODE );
- DALI_TEST_EQUALS( blendModeValue.Get<int>(), (int)BlendMode::ON, TEST_LOCATION );
-
- animation.AnimateTo( Property(actor, Actor::Property::COLOR), Color::WHITE );
- animation.Play();
-
- application.SendNotification();
- application.Render(0);
- application.Render(2000u); // halfway point
- Vector4 testColor(1.0f, 0.0f, 0.5f, 0.75f );
-
- DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue<Vector4>("uColor", Vector4(0.5f, 0.5f, 0.5f, 1.0f )), true, TEST_LOCATION );
- DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue<Vector3>("mixColor", Vector3(testColor)), true, TEST_LOCATION );
- DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue<float>("opacity", testColor.a), true, TEST_LOCATION );
-
- application.Render(2000u); // halfway point between blue and white
-
- DALI_TEST_EQUALS( actor.GetCurrentColor(), Color::WHITE, TEST_LOCATION );
- DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue<Vector4>("uColor", Color::WHITE ), true, TEST_LOCATION );
- DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue<Vector3>("mixColor", Vector3(TARGET_MIX_COLOR)), true, TEST_LOCATION );
- DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue<float>("opacity", TARGET_MIX_COLOR.a), true, TEST_LOCATION );
-
- TestMixColor( visual, DevelVisual::Property::MIX_COLOR, TARGET_MIX_COLOR );
-
- blendModeValue = renderer.GetProperty( Renderer::Property::BLEND_MODE );
- DALI_TEST_EQUALS( blendModeValue.Get<int>(), (int)BlendMode::ON, TEST_LOCATION );
-
- END_TEST;
-}
-
-
-int UtcDaliVisualAnimateImageVisualOpacity(void)
-{
- ToolkitTestApplication application;
- tet_infoline( "UtcDaliAnimateImageVisual mix color" );
-
- application.GetPlatform().SetClosestImageSize( Vector2(100, 100) );
-
- VisualFactory factory = VisualFactory::Get();
- Property::Map propertyMap;
- propertyMap.Insert(Visual::Property::TYPE, Visual::IMAGE);
- propertyMap.Insert(ImageVisual::Property::URL, TEST_IMAGE_FILE_NAME );
- propertyMap.Insert("opacity", 0.5f);
- propertyMap.Insert(ImageVisual::Property::SYNCHRONOUS_LOADING, true);
- Visual::Base visual = factory.CreateVisual( propertyMap );
-
- DummyControl actor = DummyControl::New(true);
- Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(actor.GetImplementation());
- dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
-
- actor.SetSize(2000, 2000);
- actor.SetParentOrigin(ParentOrigin::CENTER);
- actor.SetColor(Color::BLACK);
- Stage::GetCurrent().Add(actor);
-
- DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION);
-
- Renderer renderer = actor.GetRendererAt(0);
- tet_infoline("Test that the renderer has the opacity property");
- Property::Index index = DevelHandle::GetPropertyIndex( renderer, DevelVisual::Property::OPACITY );
- DALI_TEST_CHECK( index != Property::INVALID_INDEX );
-
-
- Property::Value blendModeValue = renderer.GetProperty( Renderer::Property::BLEND_MODE );
- DALI_TEST_EQUALS( blendModeValue.Get<int>(), (int)BlendMode::ON, TEST_LOCATION );
-
- {
- tet_infoline( "Test that the opacity can be increased to full via animation, and that the blend mode is set appropriately at the start and end of the animation." );
-
- Property::Map map;
- map["target"] = "testVisual";
- map["property"] = "opacity";
- map["targetValue"] = 1.0f;
- map["animator"] = Property::Map()
- .Add("alphaFunction", "LINEAR")
- .Add("timePeriod", Property::Map()
- .Add("delay", 0.0f)
- .Add("duration", 4.0f));
-
- Dali::Toolkit::TransitionData transition = TransitionData::New( map );
- Animation animation = dummyImpl.CreateTransition( transition );
- animation.Play();
-
- application.SendNotification();
- application.Render(0);
- application.Render(2000u); // halfway point
- application.SendNotification();
-
- DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue<float>("opacity", 0.75f), true, TEST_LOCATION );
-
- application.Render(2001u); // end
- application.SendNotification();
-
- DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue<float>("opacity", 1.0f), true, TEST_LOCATION );
-
- blendModeValue = renderer.GetProperty( Renderer::Property::BLEND_MODE );
- DALI_TEST_EQUALS( blendModeValue.Get<int>(), (int)BlendMode::AUTO, TEST_LOCATION );
- }
-
-
- {
- tet_infoline( "Test that the opacity can be reduced via animation, and that the blend mode is set appropriately at the start and end of the animation." );
-
- Property::Map map;
- map["target"] = "testVisual";
- map["property"] = DevelVisual::Property::OPACITY;
- map["targetValue"] = 0.1f;
- map["animator"] = Property::Map()
- .Add("alphaFunction", "LINEAR")
- .Add("timePeriod", Property::Map()
- .Add("delay", 0.0f)
- .Add("duration", 4.0f));
-
- Dali::Toolkit::TransitionData transition = TransitionData::New( map );
- Animation animation = dummyImpl.CreateTransition( transition );
- animation.Play();
-
- blendModeValue = renderer.GetProperty( Renderer::Property::BLEND_MODE );
- DALI_TEST_EQUALS( blendModeValue.Get<int>(), (int)BlendMode::ON, TEST_LOCATION );
-
- application.SendNotification();
- application.Render(0);
- application.Render(2000u); // halfway point
- application.SendNotification();
-
- DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue<float>("opacity", 0.55f), true, TEST_LOCATION );
-
- application.Render(2016u); // end
- application.SendNotification();
-
- DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue<float>("opacity", 0.1f), true, TEST_LOCATION );
-
- blendModeValue = renderer.GetProperty( Renderer::Property::BLEND_MODE );
- DALI_TEST_EQUALS( blendModeValue.Get<int>(), (int)BlendMode::ON, TEST_LOCATION );
- }
-
-
- END_TEST;
-}
-
-int UtcDaliVisualAnimateImageVisualPixelArea(void)
-{
- ToolkitTestApplication application;
- tet_infoline( "UtcDaliAnimateImageVisual pixel area" );
-
- application.GetPlatform().SetClosestImageSize( Vector2(100, 100) );
-
- VisualFactory factory = VisualFactory::Get();
- Property::Map propertyMap;
- propertyMap.Insert(Visual::Property::TYPE, Visual::IMAGE);
- propertyMap.Insert(ImageVisual::Property::URL, TEST_IMAGE_FILE_NAME );
- propertyMap.Insert("mixColor", Color::BLUE);
- propertyMap.Insert(ImageVisual::Property::SYNCHRONOUS_LOADING, true);
- Visual::Base visual = factory.CreateVisual( propertyMap );
-
- DummyControl actor = DummyControl::New(true);
- Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(actor.GetImplementation());
- dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
-
- actor.SetSize(2000, 2000);
- actor.SetParentOrigin(ParentOrigin::CENTER);
- actor.SetColor(Color::BLACK);
- Stage::GetCurrent().Add(actor);
-
- DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION);
-
- Renderer renderer = actor.GetRendererAt(0);
- Property::Index index = DevelHandle::GetPropertyIndex( renderer, DevelVisual::Property::MIX_COLOR );
-
- tet_infoline("Test that the renderer has the mixColor property");
- DALI_TEST_CHECK( index != Property::INVALID_INDEX );
-
- // TransitionData only takes string keys
- Property::Map map;
- map["target"] = "testVisual";
- map["property"] = "pixelArea";
- map["initialValue"] = Vector4( 0,0,0,1 );
- map["targetValue"] = Vector4( 0,0,1,1 ); // Animate width from zero to full
- map["animator"] = Property::Map()
- .Add("alphaFunction", "LINEAR")
- .Add("timePeriod", Property::Map()
- .Add("delay", 0.0f)
- .Add("duration", 4.0f));
-
- Dali::Toolkit::TransitionData transition = TransitionData::New( map );
-
- Animation animation = dummyImpl.CreateTransition( transition );
- animation.AnimateTo( Property(actor, Actor::Property::COLOR), Color::WHITE );
- animation.Play();
-
- application.SendNotification();
- application.Render(0);
- application.Render(2000u); // halfway point
-
- DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue<Vector4>("pixelArea", Vector4(0.0f, 0.0f, 0.5f, 1.0f )), true, TEST_LOCATION );
-
- application.Render(2000u);
-
- DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue<Vector4>("pixelArea", Vector4( 0.0f, 0.0f, 1.0f, 1.0f )), true, TEST_LOCATION );
-
- END_TEST;
-}
-
int UtcDaliVisualWireframeVisual(void)
{
{
typedef NinePatchImage::StretchRanges StretchRanges;
-const char* TEST_IMAGE_FILE_NAME = "gallery_image_01.jpg";
-const char* TEST_NPATCH_FILE_NAME = "gallery_image_01.9.png";
+const char* TEST_NPATCH_FILE_NAME = TEST_RESOURCE_DIR "/button-up-1.9.png";
const char* TEST_SVG_FILE_NAME = TEST_RESOURCE_DIR "/svg1.svg";
const char* TEST_OBJ_FILE_NAME = TEST_RESOURCE_DIR "/Cube.obj";
const char* TEST_MTL_FILE_NAME = TEST_RESOURCE_DIR "/ToyRobot-Metal.mtl";
// resolution: 34*34, pixel format: RGBA8888
static const char* gImage_34_RGBA = TEST_RESOURCE_DIR "/icon-edit.png";
-// resolution: 600*600, pixel format: RGB888
-static const char* gImage_600_RGB = TEST_RESOURCE_DIR "/test-image-600.jpg";
+
Property::Map DefaultTransform()
{
END_TEST;
}
-int UtcDaliVisualFactoryGetImageVisual1(void)
-{
- ToolkitTestApplication application;
- tet_infoline( "UtcDaliVisualFactoryGetImageVisual1: Request image visual with a Property::Map" );
-
- VisualFactory factory = VisualFactory::Get();
- DALI_TEST_CHECK( factory );
-
- Property::Map propertyMap;
- propertyMap.Insert( Visual::Property::TYPE, Visual::IMAGE );
- propertyMap.Insert( ImageVisual::Property::URL, TEST_IMAGE_FILE_NAME );
-
- Visual::Base visual = factory.CreateVisual( propertyMap );
- DALI_TEST_CHECK( visual );
-
- // For tesing the LoadResourceFunc is called, a big image size should be set, so the atlasing is not applied.
- // Image with a size smaller than 512*512 will be uploaded as a part of the atlas.
-
- const int width=512;
- const int height=513;
- TestGlAbstraction& gl = application.GetGlAbstraction();
- TraceCallStack& textureTrace = gl.GetTextureTrace();
- textureTrace.Enable(true);
-
- Integration::Bitmap* bitmap = Integration::Bitmap::New( Integration::Bitmap::BITMAP_2D_PACKED_PIXELS, ResourcePolicy::OWNED_DISCARD );
- bitmap->GetPackedPixelsProfile()->ReserveBuffer( Pixel::RGBA8888, width, height,width, height );
-
- DummyControl actor = DummyControl::New();
- TestVisualRender( application, actor, visual, 1u,
- ImageDimensions(width, height),
- Integration::ResourcePointer( bitmap ) );
-
- DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
-
- Stage::GetCurrent().Remove( actor );
- DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
-
- END_TEST;
-}
-
-int UtcDaliVisualFactoryGetImageVisual2(void)
-{
- ToolkitTestApplication application;
- tet_infoline( "UtcDaliVisualFactoryGetImageVisual2: Request image visual with an image handle" );
- VisualFactory factory = VisualFactory::Get();
- DALI_TEST_CHECK( factory );
-
- Image image = ResourceImage::New(TEST_IMAGE_FILE_NAME);
- Visual::Base visual = factory.CreateVisual( image );
-
- // For tesing the LoadResourceFunc is called, a big image size should be set, so the atlasing is not applied.
- // Image with a size smaller than 512*512 will be uploaded as a part of the atlas.
-
- const int width=512;
- const int height=513;
-
- Integration::Bitmap* bitmap = Integration::Bitmap::New( Integration::Bitmap::BITMAP_2D_PACKED_PIXELS, ResourcePolicy::OWNED_DISCARD );
- bitmap->GetPackedPixelsProfile()->ReserveBuffer( Pixel::RGBA8888, width, height,width, height );
- TestGlAbstraction& gl = application.GetGlAbstraction();
- TraceCallStack& textureTrace = gl.GetTextureTrace();
- textureTrace.Enable(true);
- DummyControl actor = DummyControl::New();
- TestVisualRender( application, actor, visual, 1u,
- ImageDimensions(width, height),
- Integration::ResourcePointer(bitmap) );
-
- DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
- END_TEST;
-}
-
-int UtcDaliVisualFactoryGetImageVisual3(void)
-{
- ToolkitTestApplication application;
- tet_infoline( "UtcDaliVisualFactoryGetImageVisual3: Request image visual with a Property::Map, test custom wrap mode and pixel area with atlasing" );
-
- VisualFactory factory = VisualFactory::Get();
- DALI_TEST_CHECK( factory );
-
- // Test wrap mode with atlasing. Image with a size smaller than 512*512 will be uploaded as a part of the atlas.
- const int width=34;
- const int height=34;
- const Vector4 pixelArea(-0.5f, -0.5f, 2.f, 2.f);
-
- Property::Map propertyMap;
- propertyMap.Insert( Visual::Property::TYPE, Visual::IMAGE );
- propertyMap.Insert( ImageVisual::Property::URL, gImage_34_RGBA );
- propertyMap.Insert( ImageVisual::Property::DESIRED_WIDTH, width );
- propertyMap.Insert( ImageVisual::Property::DESIRED_HEIGHT, height );
- propertyMap.Insert( ImageVisual::Property::SYNCHRONOUS_LOADING, true );
- propertyMap.Insert( ImageVisual::Property::PIXEL_AREA, pixelArea );
- propertyMap.Insert( ImageVisual::Property::WRAP_MODE_U, WrapMode::MIRRORED_REPEAT );
- propertyMap.Insert( ImageVisual::Property::WRAP_MODE_V, WrapMode::REPEAT );
- propertyMap.Insert( DevelImageVisual::Property::ATLASING, true );
-
- Visual::Base visual = factory.CreateVisual( propertyMap );
- DALI_TEST_CHECK( visual );
-
- TestGlAbstraction& gl = application.GetGlAbstraction();
- TraceCallStack& textureTrace = gl.GetTextureTrace();
- textureTrace.Enable(true);
- TraceCallStack& texParameterTrace = gl.GetTexParameterTrace();
- texParameterTrace.Enable( true );
-
- DummyControl actor = DummyControl::New();
- DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
- dummyImpl.RegisterVisual( Control::CONTROL_PROPERTY_END_INDEX + 1, visual );
- actor.SetSize(2000, 2000);
- actor.SetParentOrigin(ParentOrigin::CENTER);
- Stage::GetCurrent().Add( actor );
-
- // loading started
- application.SendNotification();
- application.Render();
- application.Render();
- application.SendNotification();
- BitmapLoader loader = BitmapLoader::GetLatestCreated();
- DALI_TEST_CHECK( loader );
- loader.WaitForLoading();// waiting until the image to be loaded
- DALI_TEST_CHECK( loader.IsLoaded() );
-
- DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
-
- DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
-
- // WITH atlasing, the wrapping is handled manually in shader, so the following gl function should not be called
- std::stringstream out;
- out << GL_TEXTURE_2D << ", " << GL_TEXTURE_WRAP_S << ", " << GL_MIRRORED_REPEAT;
- DALI_TEST_CHECK( !texParameterTrace.FindMethodAndParams("TexParameteri", out.str()) );
- out.str("");
- out << GL_TEXTURE_2D << ", " << GL_TEXTURE_WRAP_T << ", " << GL_REPEAT;
- DALI_TEST_CHECK( !texParameterTrace.FindMethodAndParams("TexParameteri", out.str()) );
-
- // test the uniforms which used to handle the wrap mode
- Renderer renderer = actor.GetRendererAt( 0u );
- DALI_TEST_CHECK( renderer );
-
- Property::Value pixelAreaValue = renderer.GetProperty( renderer.GetPropertyIndex( "pixelArea" ) );
- DALI_TEST_EQUALS( pixelAreaValue.Get<Vector4>(), pixelArea, TEST_LOCATION );
- Vector4 pixelAreaUniform;
- DALI_TEST_CHECK( gl.GetUniformValue<Vector4>( "pixelArea", pixelAreaUniform ) );
- DALI_TEST_EQUALS( pixelArea, pixelAreaUniform, Math::MACHINE_EPSILON_100, TEST_LOCATION );
-
- Property::Value wrapModeValue = renderer.GetProperty( renderer.GetPropertyIndex( "wrapMode" ) );
- Vector2 wrapMode( WrapMode::MIRRORED_REPEAT-1, WrapMode::REPEAT-1 );
- DALI_TEST_EQUALS( wrapModeValue.Get<Vector2>(), wrapMode, TEST_LOCATION );
- Vector2 wrapModeUniform;
- DALI_TEST_CHECK( gl.GetUniformValue<Vector2>( "wrapMode", wrapModeUniform ) );
- DALI_TEST_EQUALS( wrapMode, wrapModeUniform, Math::MACHINE_EPSILON_100, TEST_LOCATION );
-
- actor.Unparent( );
- DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
-
- END_TEST;
-}
-
-int UtcDaliVisualFactoryGetImageVisual4(void)
-{
- ToolkitTestApplication application;
- tet_infoline( "UtcDaliVisualFactoryGetImageVisual4: Request image visual with a Property::Map, test custom wrap mode and pixel area without atlasing" );
-
- VisualFactory factory = VisualFactory::Get();
- DALI_TEST_CHECK( factory );
-
- // Test wrap mode without atlasing. Image with a size bigger than 512*512 will NOT be uploaded as a part of the atlas.
- const int width=600;
- const int height=600;
- const Vector4 pixelArea(-0.5f, -0.5f, 2.f, 2.f);
-
- Property::Map propertyMap;
- propertyMap.Insert( Visual::Property::TYPE, Visual::IMAGE );
- propertyMap.Insert( ImageVisual::Property::URL, gImage_600_RGB );
- propertyMap.Insert( ImageVisual::Property::DESIRED_WIDTH, width );
- propertyMap.Insert( ImageVisual::Property::DESIRED_HEIGHT, height );
- propertyMap.Insert( ImageVisual::Property::SYNCHRONOUS_LOADING, true );
- propertyMap.Insert( ImageVisual::Property::PIXEL_AREA, pixelArea );
- propertyMap.Insert( ImageVisual::Property::WRAP_MODE_U, WrapMode::MIRRORED_REPEAT );
- propertyMap.Insert( ImageVisual::Property::WRAP_MODE_V, WrapMode::REPEAT );
-
- Visual::Base visual = factory.CreateVisual( propertyMap );
- DALI_TEST_CHECK( visual );
-
- TestGlAbstraction& gl = application.GetGlAbstraction();
- TraceCallStack& textureTrace = gl.GetTextureTrace();
- textureTrace.Enable(true);
- TraceCallStack& texParameterTrace = gl.GetTexParameterTrace();
- texParameterTrace.Enable( true );
-
- DummyControl actor = DummyControl::New();
- DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
- dummyImpl.RegisterVisual( Control::CONTROL_PROPERTY_END_INDEX + 1, visual );
- actor.SetSize(2000, 2000);
- actor.SetParentOrigin(ParentOrigin::CENTER);
- Stage::GetCurrent().Add( actor );
-
- // loading started
- application.SendNotification();
- application.Render();
- application.Render();
- application.SendNotification();
- BitmapLoader loader = BitmapLoader::GetLatestCreated();
- DALI_TEST_CHECK( loader );
- loader.WaitForLoading();// waiting until the image to be loaded
- DALI_TEST_CHECK( loader.IsLoaded() );
-
- DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
-
- DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
-
- // WITHOUT atlasing, the wrapping is handled by setting gl texture parameters
- std::stringstream out;
- out << GL_TEXTURE_2D << ", " << GL_TEXTURE_WRAP_S << ", " << GL_MIRRORED_REPEAT;
- DALI_TEST_CHECK( texParameterTrace.FindMethodAndParams("TexParameteri", out.str()) );
- out.str("");
- out << GL_TEXTURE_2D << ", " << GL_TEXTURE_WRAP_T << ", " << GL_REPEAT;
- DALI_TEST_CHECK( texParameterTrace.FindMethodAndParams("TexParameteri", out.str()) );
-
- // test the uniforms which used to handle the wrap mode
- Renderer renderer = actor.GetRendererAt( 0u );
- DALI_TEST_CHECK( renderer );
-
- Property::Value pixelAreaValue = renderer.GetProperty( renderer.GetPropertyIndex( "pixelArea" ) );
- DALI_TEST_EQUALS( pixelAreaValue.Get<Vector4>(), pixelArea, TEST_LOCATION );
- Vector4 pixelAreaUniform;
- DALI_TEST_CHECK( gl.GetUniformValue<Vector4>( "pixelArea", pixelAreaUniform ) );
- DALI_TEST_EQUALS( pixelArea, pixelAreaUniform, Math::MACHINE_EPSILON_100, TEST_LOCATION );
-
- Property::Index wrapModeIndex = renderer.GetPropertyIndex( "wrapMode" );
- DALI_TEST_CHECK(wrapModeIndex == Property::INVALID_INDEX);
-
- actor.Unparent();
- DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
-
- END_TEST;
-}
int UtcDaliVisualFactoryGetNPatchVisual1(void)
{
$(toolkit_src_dir)/visuals/svg/svg-visual.cpp \
$(toolkit_src_dir)/visuals/text/text-visual.cpp \
$(toolkit_src_dir)/visuals/transition-data-impl.cpp \
+ $(toolkit_src_dir)/visuals/texture-manager.cpp \
+ $(toolkit_src_dir)/visuals/texture-upload-observer.cpp \
$(toolkit_src_dir)/visuals/visual-base-data-impl.cpp \
$(toolkit_src_dir)/visuals/visual-base-impl.cpp \
$(toolkit_src_dir)/visuals/visual-factory-cache.cpp \
return internal;
}
-uint32_t AsyncImageLoader::Load( const std::string& url,
+uint32_t AsyncImageLoader::Load( const VisualUrl& url,
ImageDimensions dimensions,
FittingMode::Type fittingMode,
SamplingMode::Type samplingMode,
void AsyncImageLoader::ProcessLoadedImage()
{
- while( LoadingTask *next = mLoadThread.NextCompletedTask() )
+ while( LoadingTask *next = mLoadThread.NextCompletedTask() )
{
mLoadedSignal.Emit( next->id, next->pixelData );
delete next;
/**
* @copydoc Toolkit::AsyncImageLoader::Load( const std::string&, ImageDimensions, FittingMode::Type, SamplingMode::Type, bool )
*/
- uint32_t Load( const std::string& url,
+ uint32_t Load( const VisualUrl& url,
ImageDimensions dimensions,
FittingMode::Type fittingMode,
SamplingMode::Type samplingMode,
~AsyncImageLoader();
private:
-
Toolkit::AsyncImageLoader::ImageLoadedSignalType mLoadedSignal;
ImageLoadThread mLoadThread;
uint32_t mLoadTaskId;
bool mIsLoadThreadStarted;
-
-
};
} // namespace Internal
// EXTERNAL INCLUDES
#include <string.h>
#include <dali/public-api/signals/callback.h>
-#include <dali/public-api/images/resource-image.h>
+#include <dali/devel-api/adaptor-framework/image-loading.h>
#include <dali/devel-api/adaptor-framework/bitmap-loader.h>
#include <dali/integration-api/debug.h>
void ImageAtlas::SetBrokenImage( const std::string& brokenImageUrl )
{
- mBrokenImageSize = ResourceImage::GetImageSize( brokenImageUrl );
+ mBrokenImageSize = Dali::GetClosestImageSize( brokenImageUrl );
if(mBrokenImageSize.GetWidth() > 0 && mBrokenImageSize.GetHeight() > 0 ) // check the url is valid
{
mBrokenImageUrl = brokenImageUrl;
ImageDimensions zero;
if( size == zero ) // image size not provided
{
- dimensions = ResourceImage::GetImageSize( url );
+ dimensions = Dali::GetClosestImageSize( url );
if( dimensions == zero ) // Fail to read the image & broken image file exists
{
if( !mBrokenImageUrl.empty() )
namespace Internal
{
-LoadingTask::LoadingTask( uint32_t id, const std::string& url, ImageDimensions dimensions,
+LoadingTask::LoadingTask( uint32_t id, const VisualUrl& url, ImageDimensions dimensions,
FittingMode::Type fittingMode, SamplingMode::Type samplingMode, bool orientationCorrection )
: pixelData(),
url( url ),
void LoadingTask::Load()
{
- pixelData = Dali::LoadImageFromFile( url, dimensions, fittingMode, samplingMode, orientationCorrection );
+ if( url.IsLocal() )
+ {
+ pixelData = Dali::LoadImageFromFile( url.GetUrl(), dimensions, fittingMode, samplingMode, orientationCorrection );
+ }
+ else
+ {
+ pixelData = Dali::DownloadImageSynchronously ( url.GetUrl(), dimensions, fittingMode, samplingMode, orientationCorrection );
+ }
}
#include <dali/devel-api/threading/mutex.h>
#include <dali/devel-api/threading/thread.h>
#include <dali/devel-api/adaptor-framework/event-thread-callback.h>
-
+#include <dali-toolkit/internal/visuals/visual-url.h>
namespace Dali
{
* @param [in] samplingMode The filtering method used when sampling pixels from the input image while fitting it to desired size.
* @param [in] orientationCorrection Reorient the image to respect any orientation metadata in its header.
*/
- LoadingTask( uint32_t id, const std::string& url, ImageDimensions dimensions,
- FittingMode::Type fittingMode, SamplingMode::Type samplingMode, bool orientationCorrection );
+ LoadingTask( uint32_t id, const VisualUrl& url, ImageDimensions dimensions,
+ FittingMode::Type fittingMode, SamplingMode::Type samplingMode,
+ bool orientationCorrection );
/**
* Load the image
public:
- PixelData pixelData; ///< pixelData handle after successfull load
- std::string url; ///< url of the image to load
- uint32_t id; ///< The unique id associated with this task.
- ImageDimensions dimensions; ///< dimensions to load
- FittingMode::Type fittingMode; ///< fitting options
- SamplingMode::Type samplingMode; ///< sampling options
- bool orientationCorrection:1; ///< if orientation correction is needed
+ PixelData pixelData; ///< pixelData handle after successfull load
+ VisualUrl url; ///< url of the image to load
+ uint32_t id; ///< The unique id associated with this task.
+ ImageDimensions dimensions; ///< dimensions to load
+ FittingMode::Type fittingMode; ///< fitting options
+ SamplingMode::Type samplingMode; ///< sampling options
+ bool orientationCorrection:1; ///< if orientation correction is needed
};
// EXTERNAL HEADER
#include <dali/devel-api/images/texture-set-image.h>
-#include <dali/public-api/images/resource-image.h>
+#include <dali/devel-api/adaptor-framework/image-loading.h>
namespace Dali
{
ImageDimensions zero;
if( size == zero )
{
- dimensions = ResourceImage::GetImageSize( url );
+ dimensions = Dali::GetClosestImageSize( url );
}
// big image, atlasing is not applied
#include <dali-toolkit/public-api/visuals/image-visual-properties.h>
#include <dali-toolkit/devel-api/visuals/image-visual-properties-devel.h>
#include <dali-toolkit/devel-api/visuals/visual-properties-devel.h>
+#include <dali-toolkit/internal/visuals/texture-manager.h>
#include <dali-toolkit/internal/visuals/visual-string-constants.h>
#include <dali-toolkit/internal/visuals/visual-factory-impl.h>
#include <dali-toolkit/internal/visuals/visual-factory-cache.h>
mPlacementActor(),
mImageUrl( imageUrl ),
mDesiredSize( size ),
+ mTextureId( TextureManager::INVALID_TEXTURE_ID ),
mFittingMode( fittingMode ),
mSamplingMode( samplingMode ),
mWrapModeU( WrapMode::DEFAULT ),
mWrapModeV( WrapMode::DEFAULT ),
- mAttemptAtlasing( false )
+ mAttemptAtlasing( false ),
+ mTextureLoading( false )
{
}
mPlacementActor(),
mImageUrl(),
mDesiredSize(),
+ mTextureId( TextureManager::INVALID_TEXTURE_ID ),
mFittingMode( FittingMode::DEFAULT ),
mSamplingMode( SamplingMode::DEFAULT ),
mWrapModeU( WrapMode::DEFAULT ),
mWrapModeV( WrapMode::DEFAULT ),
- mAttemptAtlasing( false )
+ mAttemptAtlasing( false ),
+ mTextureLoading( false )
{
}
}
else if( mImageUrl.IsValid() && mImageUrl.GetLocation() == VisualUrl::LOCAL )
{
- ImageDimensions dimentions = Dali::GetClosestImageSize( mImageUrl.GetUrl() );
- naturalSize.x = dimentions.GetWidth();
- naturalSize.y = dimentions.GetHeight();
+ ImageDimensions dimensions = Dali::GetClosestImageSize( mImageUrl.GetUrl() );
+ naturalSize.x = dimensions.GetWidth();
+ naturalSize.y = dimensions.GetHeight();
return;
}
naturalSize = Vector2::ZERO;
}
-void ImageVisual::CreateRenderer( TextureSet& textures )
+void ImageVisual::CreateRenderer( TextureSet& textureSet )
{
Geometry geometry;
Shader shader;
shader.RegisterProperty( PIXEL_ALIGNED_UNIFORM_NAME, PIXEL_ALIGN_ON ); // Set default to align
mImpl->mRenderer = Renderer::New( geometry, shader );
- DALI_ASSERT_DEBUG( textures );
- mImpl->mRenderer.SetTextures( textures );
+ if( textureSet )
+ {
+ mImpl->mRenderer.SetTextures( textureSet );
+ }
+ // else still waiting for texture load to finish.
//Register transform properties
mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT );
BitmapLoader loader = BitmapLoader::New( mImageUrl.GetUrl(), mDesiredSize, mFittingMode, mSamplingMode );
loader.Load();
mPixels = loader.GetPixelData();
+ mTextureLoading = false;
}
}
TextureSet ImageVisual::CreateTextureSet( Vector4& textureRect, bool synchronousLoading, bool attemptAtlasing )
{
TextureSet textureSet;
+
+ mTextureLoading = false;
+
textureRect = FULL_TEXTURE_RECT;
if( synchronousLoading )
{
{
textureSet = mFactoryCache.GetAtlasManager()->Add( textureRect, mImageUrl.GetUrl(), mDesiredSize, mFittingMode, true, this );
mImpl->mFlags |= Impl::IS_ATLASING_APPLIED;
+ mTextureLoading = true;
}
if( !textureSet ) // big image, no atlasing or atlasing failed
{
mImpl->mFlags &= ~Impl::IS_ATLASING_APPLIED;
- ResourceImage resourceImage = Dali::ResourceImage::New( mImageUrl.GetUrl(), mDesiredSize, mFittingMode, mSamplingMode );
- resourceImage.LoadingFinishedSignal().Connect( this, &ImageVisual::OnImageLoaded );
- textureSet = TextureSet::New();
- TextureSetImage( textureSet, 0u, resourceImage );
+ TextureManager& textureManager = mFactoryCache.GetTextureManager();
+ mTextureId = textureManager.RequestLoad( mImageUrl, mDesiredSize, mFittingMode,
+ mSamplingMode, TextureManager::NO_ATLAS, 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) )
+ if( ! (mImpl->mFlags & Impl::IS_ATLASING_APPLIED) && textureSet )
{
Sampler sampler = Sampler::New();
sampler.SetWrapMode( mWrapModeU, mWrapModeV );
textureSet.SetSampler( 0u, sampler );
}
+
return textureSet;
}
{
mImpl->mFlags &= ~Impl::IS_ATLASING_APPLIED;
- if( !mImpl->mCustomShader && mImageUrl.GetLocation() == VisualUrl::LOCAL )
+ if( ! mImpl->mCustomShader && mImageUrl.GetLocation() == VisualUrl::LOCAL )
{
bool defaultWrapMode = mWrapModeU <= WrapMode::CLAMP_TO_EDGE && mWrapModeV <= WrapMode::CLAMP_TO_EDGE;
ApplyImageToSampler( 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 )
{
if( mImageUrl.IsValid() )
}
mPlacementActor = actor;
-
// Search the Actor tree to find if Layer UI behaviour set.
Layer layer = actor.GetLayer();
if ( layer && layer.GetBehavior() == Layer::LAYER_3D )
mImpl->mRenderer.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, mPixelArea );
}
- if( IsSynchronousResourceLoading() || !(mImpl->mFlags & Impl::IS_ATLASING_APPLIED) )
+ if( mTextureLoading == false )
{
actor.AddRenderer( mImpl->mRenderer );
mPlacementActor.Reset();
actor.RemoveRenderer( mImpl->mRenderer);
if( mImageUrl.IsValid() )
{
- RemoveFromAtlas( mImageUrl.GetUrl() );
+ RemoveTexture( mImageUrl.GetUrl() );
mImage.Reset();
}
-
+ mTextureLoading = false;
mImpl->mRenderer.Reset();
mPlacementActor.Reset();
}
}
}
-void ImageVisual::OnImageLoaded( ResourceImage image )
+// From existing atlas manager
+void ImageVisual::UploadCompleted()
{
- if( image.GetLoadingState() == Dali::ResourceLoadingFailed )
+ // Texture has been uploaded. 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();
+ }
+ mTextureLoading = false;
+}
+
+// From Texture Manager
+void ImageVisual::UploadComplete( bool loadingSuccess, TextureSet textureSet, bool usingAtlas, const Vector4& atlasRectangle )
+{
+ Actor actor = mPlacementActor.GetHandle();
+ if( actor )
{
- Image brokenImage = VisualFactoryCache::GetBrokenVisualImage();
if( mImpl->mRenderer )
{
- ApplyImageToSampler( brokenImage );
+ actor.AddRenderer( mImpl->mRenderer );
+ // reset the weak handle so that the renderer only get added to actor once
+ mPlacementActor.Reset();
+
+ if( loadingSuccess )
+ {
+ Sampler sampler = Sampler::New();
+ sampler.SetWrapMode( mWrapModeU, mWrapModeV );
+ textureSet.SetSampler( 0u, sampler );
+ mImpl->mRenderer.SetTextures(textureSet);
+ }
+ else
+ {
+ Image brokenImage = VisualFactoryCache::GetBrokenVisualImage();
+ ApplyImageToSampler( brokenImage );
+ }
}
}
+ mTextureLoading = false;
}
-void ImageVisual::RemoveFromAtlas(const std::string& url)
+void ImageVisual::RemoveTexture(const std::string& url)
{
- 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( mTextureId != TextureManager::INVALID_TEXTURE_ID )
{
- Property::Value atlasRectValue = mImpl->mRenderer.GetProperty( index );
- atlasRectValue.Get( atlasRect );
+ mFactoryCache.GetTextureManager().Remove( mTextureId );
+ mTextureId = TextureManager::INVALID_TEXTURE_ID;
}
+ else
+ {
+ 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 );
+ }
- TextureSet textureSet = mImpl->mRenderer.GetTextures();
- mImpl->mRenderer.Reset();
+ TextureSet textureSet = mImpl->mRenderer.GetTextures();
+ mImpl->mRenderer.Reset();
- if( index != Property::INVALID_INDEX )
- {
- mFactoryCache.GetAtlasManager()->Remove( textureSet, atlasRect );
+ if( index != Property::INVALID_INDEX )
+ {
+ mFactoryCache.GetAtlasManager()->Remove( textureSet, atlasRect );
+ }
}
}
// INTERNAL INCLUDES
#include <dali-toolkit/devel-api/image-loader/atlas-upload-observer.h>
+#include <dali-toolkit/internal/visuals/texture-upload-observer.h>
#include <dali-toolkit/internal/visuals/visual-base-impl.h>
#include <dali-toolkit/internal/visuals/visual-url.h>
* If the Visual is in a LayerUI it will pixel align the image, using a Layer3D will disable pixel alignment.
* Changing layer behaviour between LayerUI to Layer3D whilst the visual is already staged will not have an effect.
*/
-class ImageVisual: public Visual::Base, public ConnectionTracker, public AtlasUploadObserver
+class ImageVisual: public Visual::Base, public ConnectionTracker, public AtlasUploadObserver, public TextureUploadObserver
{
public:
*/
virtual void UploadCompleted();
+ /**
+ * @copydoc TextureUploadObserver::UploadCompleted
+ *
+ * To avoid rendering garbage pixels, renderer should be added to actor after the resources are ready.
+ * This callback is the place to add the renderer as it would be called once the loading is finished.
+ */
+ virtual void UploadComplete( bool success, TextureSet textureSet, bool usingAtlas, const Vector4& atlasRectangle );
+
private:
/**
TextureSet CreateTextureSet( Vector4& textureRect, bool synchronousLoading, bool attemptAtlasing );
/**
- * Callback function of image resource loading succeed
- * @param[in] image The Image content that we attempted to load from mImageUrl
- */
- void OnImageLoaded( ResourceImage image );
-
- /**
* Set the value to the uTextureRect uniform
* @param[in] textureRect The texture rectangular area.
*/
void SetTextureRectUniform( const Vector4& textureRect );
/**
- * Remove the image from atlas if it is not used anymore.
+ * Remove the texture if it is not used anymore.
*/
- void RemoveFromAtlas(const std::string& url);
+ void RemoveTexture(const std::string& url);
/**
* Helper method to set individual values by index key.
VisualUrl mImageUrl;
Dali::ImageDimensions mDesiredSize;
+ TextureManager::TextureId mTextureId;
+
Dali::FittingMode::Type mFittingMode:3;
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 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.
};
} // namespace Internal
--- /dev/null
+ /*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "texture-manager.h"
+
+// EXTERNAL HEADERS
+#include <dali/devel-api/common/hash.h>
+#include <dali/devel-api/images/texture-set-image.h>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL HEADERS
+#include <dali/integration-api/debug.h>
+#include <dali-toolkit/internal/image-loader/async-image-loader-impl.h>
+#include <dali-toolkit/internal/image-loader/image-atlas-impl.h>
+#include <dali-toolkit/public-api/image-loader/sync-image-loader.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+
+#ifdef DEBUG_ENABLED
+Debug::Filter* gTextureManagerLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_TEXTURE_MANAGER" );
+#endif
+
+const uint32_t DEFAULT_ATLAS_SIZE( 1024u ); ///< This size can fit 8 by 8 images of average size 128 * 128
+const Vector4 FULL_ATLAS_RECT( 0.0f, 0.0f, 1.0f, 1.0f ); ///< UV Rectangle that covers the full Texture
+const char * const BROKEN_IMAGE_URL( DALI_IMAGE_DIR "broken.png" ); ///< URL For the broken image placeholder
+const int INVALID_INDEX( -1 ); ///< Invalid index used to represent a non-existant TextureInfo struct
+const int INVALID_CACHE_INDEX( -1 ); ///< Invalid Cache index
+
+} // Anonymous namespace
+
+
+TextureManager::TextureManager()
+: mAsyncLocalLoader( Toolkit::AsyncImageLoader::New() ),
+ mAsyncRemoteLoader( Toolkit::AsyncImageLoader::New() ),
+ mCurrentTextureId( 0 )
+{
+ mAsyncLocalLoader.ImageLoadedSignal().Connect( this, &TextureManager::AsyncLocalLoadComplete );
+ mAsyncRemoteLoader.ImageLoadedSignal().Connect( this, &TextureManager::AsyncRemoteLoadComplete );
+}
+
+TextureManager::TextureId TextureManager::RequestLoad(
+ const VisualUrl& url,
+ const ImageDimensions desiredSize,
+ FittingMode::Type fittingMode,
+ Dali::SamplingMode::Type samplingMode,
+ const UseAtlas useAtlas,
+ TextureUploadObserver* observer )
+{
+ // First check if the requested Texture is cached.
+ const TextureHash textureHash = GenerateHash( url.GetUrl(), desiredSize, fittingMode, samplingMode, useAtlas );
+
+ // Look up the texture by hash. Note: The extra parameters are used in case of a hash collision.
+ int cacheIndex = FindCachedTexture( textureHash, url.GetUrl(), desiredSize, fittingMode, samplingMode, useAtlas );
+ TextureManager::TextureId textureId = INVALID_TEXTURE_ID;
+
+ // Check if the requested Texture exists in the cache.
+ if( cacheIndex != INVALID_CACHE_INDEX )
+ {
+ // Mark this texture being used by another client resource.
+ ++( mTextureInfoContainer[ cacheIndex ].referenceCount );
+ textureId = mTextureInfoContainer[ cacheIndex ].textureId;
+
+ DALI_LOG_INFO( gTextureManagerLogFilter, Debug::Concise, "TextureManager::RequestLoad( url=%s observer=%p ) Using cached texture @%d, textureId=%d\n", url.GetUrl().c_str(), observer, cacheIndex, textureId );
+ }
+ else
+ {
+ // We need a new Texture.
+ textureId = GenerateUniqueTextureId();
+ mTextureInfoContainer.push_back( TextureInfo( textureId, url.GetUrl(), desiredSize, fittingMode, samplingMode, false, useAtlas, textureHash ) );
+ cacheIndex = mTextureInfoContainer.size() - 1u;
+
+ DALI_LOG_INFO( gTextureManagerLogFilter, Debug::Concise, "TextureManager::RequestLoad( url=%s observer=%p ) New texture, cacheIndex:%d, textureId=%d\n", url.GetUrl().c_str(), observer, cacheIndex, textureId );
+ }
+
+ // The below code path is common whether we are using the cache or not.
+ // The textureInfoIndex now refers to either a pre-existing cached TextureInfo, or a new TextureInfo just created.
+ TextureInfo& textureInfo( mTextureInfoContainer[ cacheIndex ] );
+
+ DALI_LOG_INFO( gTextureManagerLogFilter, Debug::Concise, "TextureInfo loadState:%s\n",
+ textureInfo.loadState == TextureManager::NOT_STARTED ? "NOT_STARTED" :
+ textureInfo.loadState == TextureManager::LOADING ? "LOADING" :
+ textureInfo.loadState == TextureManager::UPLOADED ? "UPLOADED" :
+ textureInfo.loadState == TextureManager::CANCELLED ? "CANCELLED" : "Unknown" );
+
+ // Check if we should add the observer. Only do this if we have not loaded yet and it will not have loaded by the end of this method.
+ switch( textureInfo.loadState )
+ {
+ case TextureManager::NOT_STARTED:
+ {
+ LoadTexture( textureInfo );
+ ObserveTexture( textureInfo, observer );
+ break;
+ }
+ case TextureManager::LOADING:
+ {
+ ObserveTexture( textureInfo, observer );
+ break;
+ }
+ case TextureManager::UPLOADED:
+ {
+ if( observer )
+ {
+ // The Texture has already loaded. The other observers have already been notified.
+ // We need to send a "late" loaded notification for this observer.
+ observer->UploadComplete( textureInfo.loadingSucceeded,
+ textureInfo.textureSet, textureInfo.useAtlas,
+ textureInfo.atlasRect );
+ }
+ break;
+ }
+ case TextureManager::CANCELLED:
+ {
+ // A cancelled texture hasn't finished loading yet. Treat as a loading texture
+ // (it's ref count has already been incremented, above)
+ textureInfo.loadState = TextureManager::LOADING;
+ ObserveTexture( textureInfo, observer );
+ break;
+ }
+ }
+
+ // Return the TextureId for which this Texture can now be referenced by externally.
+ return textureId;
+}
+
+void TextureManager::Remove( const TextureManager::TextureId textureId )
+{
+ int textureInfoIndex = GetCacheIndexFromId( textureId );
+ if( textureInfoIndex != INVALID_INDEX )
+ {
+ TextureInfo& textureInfo( mTextureInfoContainer[ textureInfoIndex ] );
+
+
+ DALI_LOG_INFO( gTextureManagerLogFilter, Debug::Concise, "TextureManager::Remove(%d) cacheIdx:%d loadState:%s\n",
+ textureId, textureInfoIndex,
+ textureInfo.loadState == TextureManager::NOT_STARTED ? "NOT_STARTED" :
+ textureInfo.loadState == TextureManager::LOADING ? "LOADING" :
+ textureInfo.loadState == TextureManager::UPLOADED ? "UPLOADED" :
+ textureInfo.loadState == TextureManager::CANCELLED ? "CANCELLED" : "Unknown" );
+
+ // Decrement the reference count and check if this is the last user of this Texture.
+ if( --textureInfo.referenceCount <= 0 )
+ {
+ // This is the last remove for this Texture.
+ textureInfo.referenceCount = 0;
+ bool removeTextureInfo = false;
+
+ // If loaded, we can remove the TextureInfo and the Atlas (if atlased).
+ if( textureInfo.loadState == UPLOADED )
+ {
+ if( textureInfo.atlas )
+ {
+ textureInfo.atlas.Remove( textureInfo.atlasRect );
+ }
+ removeTextureInfo = true;
+ }
+ else if( textureInfo.loadState == LOADING )
+ {
+ // We mark the textureInfo for removal.
+ // Once the load has completed, this method will be called again.
+ textureInfo.loadState = CANCELLED;
+ }
+ else
+ {
+ // In other states, we are not waiting for a load so we are safe to remove the TextureInfo data.
+ removeTextureInfo = true;
+ }
+
+ // If the state allows us to remove the TextureInfo data, we do so.
+ if( removeTextureInfo )
+ {
+ // Permanently remove the textureInfo struct.
+ mTextureInfoContainer.erase( mTextureInfoContainer.begin() + textureInfoIndex );
+ }
+ }
+ }
+}
+
+TextureManager::LoadState TextureManager::GetTextureState( TextureId textureId )
+{
+ LoadState loadState = TextureManager::NOT_STARTED;
+
+ int cacheIndex = GetCacheIndexFromId( textureId );
+ if( cacheIndex != INVALID_CACHE_INDEX )
+ {
+ TextureInfo& cachedTextureInfo( mTextureInfoContainer[ cacheIndex ] );
+ loadState = cachedTextureInfo.loadState;
+ }
+ return loadState;
+}
+
+TextureSet TextureManager::GetTextureSet( TextureId textureId )
+{
+ TextureSet textureSet;// empty handle
+
+ int cacheIndex = GetCacheIndexFromId( textureId );
+ if( cacheIndex != INVALID_CACHE_INDEX )
+ {
+ TextureInfo& cachedTextureInfo( mTextureInfoContainer[ cacheIndex ] );
+ textureSet = cachedTextureInfo.textureSet;
+ }
+ return textureSet;
+}
+
+
+
+bool TextureManager::LoadTexture( TextureInfo& textureInfo )
+{
+ bool success = true;
+
+ if( textureInfo.loadState == NOT_STARTED )
+ {
+ textureInfo.loadState = LOADING;
+
+ if( !textureInfo.loadSynchronously )
+ {
+ if( textureInfo.url.IsLocal() )
+ {
+ mAsyncLocalLoadingInfoContainer.push_back( AsyncLoadingInfo( textureInfo.textureId ) );
+ mAsyncLocalLoadingInfoContainer.back().loadId = GetImplementation(mAsyncLocalLoader).Load(
+ textureInfo.url, textureInfo.desiredSize,
+ textureInfo.fittingMode, textureInfo.samplingMode, true );
+ }
+ else
+ {
+ mAsyncRemoteLoadingInfoContainer.push_back( AsyncLoadingInfo( textureInfo.textureId ) );
+ mAsyncRemoteLoadingInfoContainer.back().loadId = GetImplementation(mAsyncRemoteLoader).Load(
+ textureInfo.url, textureInfo.desiredSize,
+ textureInfo.fittingMode, textureInfo.samplingMode, true );
+ }
+ }
+ }
+
+ return success;
+}
+
+void TextureManager::ObserveTexture( TextureInfo& textureInfo,
+ TextureUploadObserver* observer )
+{
+ if( observer )
+ {
+ textureInfo.observerList.PushBack( observer );
+ observer->DestructionSignal().Connect( this, &TextureManager::ObserverDestroyed );
+ }
+}
+
+void TextureManager::AsyncLocalLoadComplete( uint32_t id, PixelData pixelData )
+{
+ AsyncLoadComplete( mAsyncLocalLoadingInfoContainer, id, pixelData );
+}
+
+void TextureManager::AsyncRemoteLoadComplete( uint32_t id, PixelData pixelData )
+{
+ AsyncLoadComplete( mAsyncRemoteLoadingInfoContainer, id, pixelData );
+}
+
+void TextureManager::AsyncLoadComplete( AsyncLoadingInfoContainerType& loadingContainer, uint32_t id, PixelData pixelData )
+{
+ DALI_LOG_INFO( gTextureManagerLogFilter, Debug::Concise, "TextureManager::AsyncLoadComplete( id:%d )\n", id );
+
+ if( loadingContainer.size() >= 1u )
+ {
+ AsyncLoadingInfo loadingInfo = loadingContainer.front();
+
+ if( loadingInfo.loadId == id )
+ {
+ int cacheIndex = GetCacheIndexFromId( loadingInfo.textureId );
+ if( cacheIndex != INVALID_CACHE_INDEX )
+ {
+ // Once we have found the TextureInfo data, we call a common function used to process loaded data for both sync and async loads.
+ TextureInfo& textureInfo( mTextureInfoContainer[cacheIndex] );
+
+ DALI_LOG_INFO( gTextureManagerLogFilter, Debug::Concise, " CacheIndex:%d LoadState: %d\n", cacheIndex, textureInfo.loadState );
+
+ // Only perform atlasing if the load has not been cancelled since the request.
+ if( textureInfo.loadState != CANCELLED )
+ {
+ // Perform atlasing and finalize the load.
+ PostLoad( textureInfo, pixelData );
+ }
+ else
+ {
+ Remove( textureInfo.textureId );
+ }
+ }
+ }
+
+ loadingContainer.pop_front();
+ }
+}
+
+
+bool TextureManager::PostLoad( TextureInfo& textureInfo, PixelData pixelData )
+{
+ bool success = false;
+
+ // Was the load successful?
+ if( pixelData && ( pixelData.GetWidth() != 0 ) && ( pixelData.GetHeight() != 0 ) )
+ {
+ // Regardless of whether the atlasing succeeds or not, we have a valid image, so we mark it as successful.
+ success = true;
+
+ bool usingAtlas = false;
+
+ // No atlas support for now
+ textureInfo.useAtlas = NO_ATLAS;
+
+ if( ! usingAtlas )
+ {
+ DALI_LOG_INFO( gTextureManagerLogFilter, Debug::Concise, " TextureManager::PostLoad() textureId:%d\n", textureInfo.textureId );
+
+ Texture texture = Texture::New( Dali::TextureType::TEXTURE_2D, pixelData.GetPixelFormat(), pixelData.GetWidth(), pixelData.GetHeight() );
+ texture.Upload( pixelData );
+ textureInfo.textureSet = TextureSet::New();
+ textureInfo.textureSet.SetTexture( 0u, texture );
+ }
+ }
+
+ if( ! success )
+ {
+ DALI_LOG_ERROR( "TextureManager::AsyncImageLoad(%s) failed\n", textureInfo.url.GetUrl().c_str() );
+ // @todo If the load was unsuccessful, upload the broken image.
+ }
+
+ // Update the load state.
+ // Note: This is regardless of success as we care about whether a
+ // load attempt is in progress or not. If unsuccessful, a broken
+ // image is still loaded.
+ textureInfo.loadState = UPLOADED;
+
+ // We need to store the load succeeded state as if a future request to load this texture comes in,
+ // we need to re-broadcast the UploadComplete notification to that observer.
+ textureInfo.loadingSucceeded = success;
+
+ // If there is an observer: Notify the load is complete, whether successful or not:
+ const unsigned int observerCount = textureInfo.observerList.Count();
+ for( unsigned int i = 0; i < observerCount; ++i )
+ {
+ TextureUploadObserver* observer = textureInfo.observerList[i];
+ if( observer )
+ {
+ observer->UploadComplete( success, textureInfo.textureSet, textureInfo.useAtlas, textureInfo.atlasRect );
+ observer->DestructionSignal().Disconnect( this, &TextureManager::ObserverDestroyed );
+ }
+ }
+
+ textureInfo.observerList.Clear();
+
+ return success;
+}
+
+TextureManager::TextureId TextureManager::GenerateUniqueTextureId()
+{
+ return mCurrentTextureId++;
+}
+
+int TextureManager::GetCacheIndexFromId( const TextureId textureId )
+{
+ const unsigned int size = mTextureInfoContainer.size();
+
+ for( unsigned int i = 0; i < size; ++i )
+ {
+ if( mTextureInfoContainer[i].textureId == textureId )
+ {
+ return i;
+ }
+ }
+
+ DALI_LOG_WARNING( "Cannot locate TextureId: %d\n", textureId );
+ return INVALID_CACHE_INDEX;
+}
+
+TextureManager::TextureHash TextureManager::GenerateHash(
+ const std::string& url,
+ const ImageDimensions size,
+ const FittingMode::Type fittingMode,
+ const Dali::SamplingMode::Type samplingMode,
+ const UseAtlas useAtlas )
+{
+ std::string hashTarget( url );
+ const size_t urlLength = hashTarget.length();
+ const uint16_t width = size.GetWidth();
+ const uint16_t height = size.GetWidth();
+
+ // If either the width or height has been specified, include the resizing options in the hash
+ if( width != 0 || height != 0 )
+ {
+ // We are appending 5 bytes to the URL to form the hash input.
+ hashTarget.resize( urlLength + 5u );
+ char* hashTargetPtr = &( hashTarget[ urlLength ] );
+
+ // Pack the width and height (4 bytes total).
+ *hashTargetPtr++ = size.GetWidth() & 0xff;
+ *hashTargetPtr++ = ( size.GetWidth() >> 8u ) & 0xff;
+ *hashTargetPtr++ = size.GetHeight() & 0xff;
+ *hashTargetPtr++ = ( size.GetHeight() >> 8u ) & 0xff;
+
+ // Bit-pack the FittingMode, SamplingMode and atlasing.
+ // FittingMode=2bits, SamplingMode=3bits, useAtlas=1bit
+ *hashTargetPtr = ( fittingMode << 4u ) | ( samplingMode << 1 ) | useAtlas;
+ }
+ else
+ {
+ // We are not including sizing information, but we still need an extra byte for atlasing.
+ hashTarget.resize( urlLength + 1u );
+ // Add the atlasing to the hash input.
+ hashTarget[ urlLength ] = useAtlas;
+ }
+
+ return Dali::CalculateHash( hashTarget );
+}
+
+int TextureManager::FindCachedTexture(
+ const TextureManager::TextureHash hash,
+ const std::string& url,
+ const ImageDimensions size,
+ const FittingMode::Type fittingMode,
+ const Dali::SamplingMode::Type samplingMode,
+ const bool useAtlas )
+{
+ // Default to an invalid ID, in case we do not find a match.
+ int cacheIndex = INVALID_CACHE_INDEX;
+
+ // Iterate through our hashes to find a match.
+ const unsigned int count = mTextureInfoContainer.size();
+ for( unsigned int i = 0u; i < count; ++i )
+ {
+ if( mTextureInfoContainer[i].hash == hash )
+ {
+ // We have a match, now we check all the original parameters in case of a hash collision.
+ TextureInfo& textureInfo( mTextureInfoContainer[i] );
+
+ if( ( url == textureInfo.url.GetUrl() ) &&
+ ( useAtlas == textureInfo.useAtlas ) &&
+ ( size == textureInfo.desiredSize ) &&
+ ( ( size.GetWidth() == 0 && size.GetHeight() == 0 ) ||
+ ( fittingMode == textureInfo.fittingMode &&
+ samplingMode == textureInfo.samplingMode ) ) )
+ {
+ // The found Texture is a match.
+ cacheIndex = i;
+ break;
+ }
+ }
+ }
+
+ return cacheIndex;
+}
+
+void TextureManager::ObserverDestroyed( TextureUploadObserver* observer )
+{
+ const unsigned int count = mTextureInfoContainer.size();
+ for( unsigned int i = 0; i < count; ++i )
+ {
+ TextureInfo& textureInfo( mTextureInfoContainer[i] );
+ for( TextureInfo::ObserverListType::Iterator j = textureInfo.observerList.Begin(); j != textureInfo.observerList.End(); ++j )
+ {
+ if( *j == observer )
+ {
+ textureInfo.observerList.Erase( j );
+ break;
+ }
+ }
+ }
+}
+
+TextureManager::~TextureManager()
+{
+ mTextureInfoContainer.clear();
+ mAsyncLocalLoadingInfoContainer.clear();
+ mAsyncRemoteLoadingInfoContainer.clear();
+}
+
+
+
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
--- /dev/null
+#ifndef DALI_TOOLKIT_TEXTURE_MANAGER_H
+#define DALI_TOOLKIT_TEXTURE_MANAGER_H
+
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// EXTERNAL INCLUDES
+#include <string>
+#include <dali/public-api/common/dali-vector.h>
+#include <dali/public-api/object/ref-object.h>
+#include <dali/public-api/rendering/texture-set.h>
+#include <dali/devel-api/common/owner-container.h>
+#include <deque>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/image-loader/image-atlas.h>
+#include <dali-toolkit/public-api/image-loader/async-image-loader.h>
+#include <dali-toolkit/internal/visuals/texture-upload-observer.h>
+#include <dali-toolkit/internal/visuals/visual-url.h>
+
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+/**
+ * The TextureManager provides a common Image loading API for Visuals.
+ *
+ * The TextureManager is responsible for providing sync, async, atlased and non-atlased loads.
+ * Texture caching is provided and performed when possible.
+ * Broken Images are automatically provided on load failure.
+ */
+class TextureManager : public ConnectionTracker
+{
+public:
+
+ typedef int32_t TextureId; ///< The TextureId type. This is used as a handle to refer to a particular Texture.
+ static const int INVALID_TEXTURE_ID = -1; ///< Used to represent a null TextureId or error
+
+ enum UseAtlas
+ {
+ NO_ATLAS,
+ USE_ATLAS
+ };
+
+ enum LoadType
+ {
+ LOAD_ASYNCHRONOUSLY,
+ LOAD_SYNCHRONOUSLY
+ };
+
+ /**
+ * @brief The LoadState Enumeration represents the current state of a particular Textures life-cycle.
+ */
+ enum LoadState
+ {
+ NOT_STARTED, ///< Default
+ LOADING, ///< Loading has been started, but not finished.
+ UPLOADED, ///< Loaded (and ready).
+ CANCELLED, ///< Removed before loading completed
+ };
+
+public:
+
+ /**
+ * Constructor.
+ */
+ TextureManager();
+
+ /**
+ * Destructor.
+ */
+ ~TextureManager();
+
+
+// TextureManager Main API:
+
+ /**
+ * @brief Requests an image load of the given URL.
+ *
+ * The parameters are used to specify how the image is loaded.
+ * The observer has the UploadComplete method called when the load is ready.
+ *
+ * When the client has finished with the Texture, Remove() should be called.
+ *
+ * @param[in] url The URL of the image to load
+ * @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] observer The client object should inherit from this and provide the "UploadCompleted" virtual.
+ * This is called when an image load completes (or fails).
+ * @return A TextureId to use as a handle to reference this Texture
+ */
+ TextureId RequestLoad( const VisualUrl& url,
+ const ImageDimensions desiredSize,
+ FittingMode::Type fittingMode,
+ Dali::SamplingMode::Type samplingMode,
+ const UseAtlas useAtlasing,
+ TextureUploadObserver* observer );
+
+ /**
+ * @brief Remove a Texture from the TextureManager.
+ *
+ * Textures are cached and therefore only the removal of the last
+ * occurrence of a Texture will cause its removal internally.
+ *
+ * @param[in] textureId The ID of the Texture to remove.
+ */
+ void Remove( const TextureManager::TextureId textureId );
+
+ /**
+ * @brief Get the current state of a texture
+ * @param[in] textureId The texture id to query
+ * @return The loading state if the texture is valid, or NOT_STARTED if the textureId
+ * is not valid.
+ */
+ LoadState GetTextureState( TextureId textureId );
+
+ /**
+ * @brief Get the associated texture set if the texture id is valid
+ * @param[in] textureId The texture Id to look up
+ * @return the associated texture set, or an empty handle if textureId is not valid
+ */
+ TextureSet GetTextureSet( TextureId textureId );
+
+private:
+
+
+ typedef size_t TextureHash; ///< The type used to store the hash used for Texture caching.
+
+ /**
+ * @brief This struct is used to manage the life-cycle of Texture loading and caching.
+ * TODO-TX: pimpl this
+ */
+ struct TextureInfo
+ {
+ TextureInfo( TextureId textureId,
+ const VisualUrl& url,
+ ImageDimensions desiredSize,
+ FittingMode::Type fittingMode,
+ Dali::SamplingMode::Type samplingMode,
+ bool loadSynchronously,
+ UseAtlas useAtlas,
+ TextureManager::TextureHash hash )
+ : url( url ),
+ desiredSize( desiredSize ),
+ useSize( desiredSize ),
+ atlasRect( 0.0f, 0.0f, 1.0f, 1.0f ), // Full atlas rectangle
+ textureId( textureId ),
+ hash( hash ),
+ referenceCount( 1u ),
+ loadState( NOT_STARTED ),
+ fittingMode( fittingMode ),
+ samplingMode( samplingMode ),
+ loadSynchronously( loadSynchronously ),
+ useAtlas( useAtlas ),
+ loadingSucceeded( false )
+ {
+ }
+
+ /**
+ * Container type used to store all observer clients of this Texture
+ */
+ typedef Dali::Vector< TextureUploadObserver* > ObserverListType;
+
+ ObserverListType observerList; ///< Container used to store all observer clients of this Texture
+ Toolkit::ImageAtlas atlas; ///< The atlas this Texture lays within (if any)
+ PixelData pixelData; ///< The PixelData holding the image data (this is used if atlasing is deferred)
+ TextureSet textureSet; ///< The TextureSet holding the Texture
+ VisualUrl url; ///< The URL of the image
+ ImageDimensions desiredSize; ///< The size requested
+ ImageDimensions useSize; ///< The size used
+ Vector4 atlasRect; ///< The atlas rect used if atlased
+ TextureId textureId; ///< The TextureId associated with this Texture
+ TextureManager::TextureHash hash; ///< The hash used to cache this Texture
+ int16_t referenceCount; ///< The reference count of clients using this Texture
+ LoadState loadState:3; ///< The load state showing the load progress of the Texture
+ FittingMode::Type fittingMode:2; ///< The requested FittingMode
+ Dali::SamplingMode::Type samplingMode:3; ///< The requested SamplingMode
+ bool loadSynchronously; ///< True if synchronous loading was requested
+ UseAtlas useAtlas; ///< USE_ATLAS if an atlas was requested. This is updated to false if atlas is not used
+ bool loadingSucceeded; ///< True if the image was loaded successfully
+ };
+
+ // Structs:
+
+ /**
+ * Struct to hold information about a requested Async load.
+ * This is used to look up a TextureManager::TextureId from the returned AsyncLoad Id.
+ */
+ struct AsyncLoadingInfo
+ {
+ AsyncLoadingInfo( TextureId textureId )
+ : textureId( textureId ),
+ loadId( 0 )
+ {
+ }
+
+ TextureId textureId; ///< The external Texture Id assigned to this load
+ 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<AsyncLoadingInfo> AsyncLoadingInfoContainerType; ///< The container type used to manage Asynchronous loads in progress
+ typedef std::vector<AtlasInfo> AtlasInfoContainerType; ///< The container type used to manage Atlas creation and destruction
+ typedef std::vector<TextureInfo> TextureInfoContainerType; ///< The container type used to manage the life-cycle and caching of Textures
+
+ /**
+ * @brief Used internally to initiate a load.
+ * @param[in] textureInfo The TextureInfo struct associated with the Texture
+ * @return True if the load was initiated
+ */
+ bool LoadTexture( TextureInfo& textureInfo );
+
+ /**
+ * Add the observer to the observer list
+ * @param[in] textureInfo The TextureInfo struct associated with the texture
+ * observer The observer wishing to observe the texture upload
+ */
+ void ObserveTexture( TextureInfo & textureInfo, TextureUploadObserver* observer );
+
+ /**
+ * @brief This signal handler is called when the async local loader finishes loading.
+ * @param[in] id This is the async image loaders Id
+ * @param[in] pixelData The loaded image data
+ */
+ void AsyncLocalLoadComplete( uint32_t id, PixelData pixelData );
+
+ /**
+ * @brief This signal handler is called when the async local loader finishes loading.
+ * @param[in] id This is the async image loaders Id
+ * @param[in] pixelData The loaded image data
+ */
+ void AsyncRemoteLoadComplete( uint32_t id, PixelData pixelData );
+
+ /**
+ * Common method to handle loading completion
+ * @param[in] container The Async loading container
+ * @param[in] id This is the async image loaders Id
+ * @param[in] pixelData The loaded image data
+ */
+ void AsyncLoadComplete( AsyncLoadingInfoContainerType& container, uint32_t id, PixelData pixelData );
+
+ /**
+ * @brief Performs Post-Load steps including atlasing.
+ * @param[in] textureInfo The struct associated with this Texture
+ * @param[in] pixelData The image pixelData
+ * @return True if successful
+ */
+ bool PostLoad( TextureManager::TextureInfo& textureInfo, PixelData pixelData );
+
+ /**
+ * @brief Generates a new, unique TextureId
+ * @return A unique TextureId
+ */
+ TextureManager::TextureId GenerateUniqueTextureId();
+
+ /**
+ * @brief Used to lookup an index into the TextureInfoContainer from a TextureId
+ * @param[in] textureId The TextureId to look up
+ * @return The cache index
+ */
+ int GetCacheIndexFromId( TextureId textureId );
+
+
+ /**
+ * @brief Generates a hash for caching based on the input parameters.
+ * @param[in] url The URL of the image to load
+ * @param[in] size The image size
+ * @param[in] fittingMode The FittingMode to use
+ * @param[in] samplingMode The SamplingMode to use
+ * @param[in] useAtlas True if atlased
+ * @return A hash of the provided data for caching.
+ */
+ TextureHash GenerateHash( const std::string& url, const ImageDimensions size,
+ const FittingMode::Type fittingMode,
+ const Dali::SamplingMode::Type samplingMode, const UseAtlas useAtlas );
+
+ /**
+ * @brief Looks up a cached texture by its hash.
+ * If found, the given parameters are used to check there is no hash-collision.
+ * @param[in] hash The hash to look up
+ * @param[in] url The URL of the image to load
+ * @param[in] size The image size
+ * @param[in] fittingMode The FittingMode to use
+ * @param[in] samplingMode The SamplingMode to use
+ * @param[in] useAtlas True if atlased
+ * @return A TextureId of a cached Texture if found. Or INVALID_TEXTURE_ID if not found.
+ */
+ TextureManager::TextureId FindCachedTexture( const TextureManager::TextureHash hash, const std::string& url, const ImageDimensions size,
+ const FittingMode::Type fittingMode, const Dali::SamplingMode::Type samplingMode, const bool useAtlas );
+
+
+private:
+
+ /**
+ * Undefined copy constructor.
+ */
+ TextureManager( const TextureManager& );
+
+ /**
+ * Undefined assignment operator.
+ */
+ TextureManager& operator=( const TextureManager& rhs );
+
+ /**
+ * This is called by the TextureManagerUploadObserver when an observer is destroyed.
+ * We use the callback to know when to remove an observer from our notify list.
+ * @param[in] observer The observer that generated the callback
+ */
+ void ObserverDestroyed( TextureUploadObserver* observer );
+
+private: // Member Variables:
+
+ AsyncLoadingInfoContainerType mAsyncLocalLoadingInfoContainer; ///< Used to manage Asynchronous loads in progress
+ AsyncLoadingInfoContainerType mAsyncRemoteLoadingInfoContainer; ///< Used to manage Asynchronous loads in progress
+ AtlasInfoContainerType mAtlasContainer; ///< Used to manage Atlas creation and destruction
+ TextureInfoContainerType mTextureInfoContainer; ///< Used to manage the life-cycle and caching of Textures
+ Toolkit::AsyncImageLoader mAsyncLocalLoader; ///< The Asynchronous image loader used to provide all local async loads
+ Toolkit::AsyncImageLoader mAsyncRemoteLoader; ///< The Asynchronous image loader used to provide all remote async loads
+ TextureId mCurrentTextureId; ///< The current value used for the unique Texture Id generation
+
+};
+
+
+} // name Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXTURE_MANAGER_H
--- /dev/null
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "texture-upload-observer.h"
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+TextureUploadObserver::TextureUploadObserver()
+{
+}
+
+TextureUploadObserver::~TextureUploadObserver()
+{
+ if( !mDestructionSignal.Empty() )
+ {
+ mDestructionSignal.Emit( this );
+ }
+}
+
+TextureUploadObserver::DestructionSignalType& TextureUploadObserver::DestructionSignal()
+{
+ return mDestructionSignal;
+}
+
+
+} // namespace Toolkit
+
+} // namespace Dali
--- /dev/null
+#ifndef DALI_TOOLKIT_INTERNAL_TEXTURE_UPLOAD_OBSERVER_H
+#define DALI_TOOLKIT_INTERNAL_TEXTURE_UPLOAD_OBSERVER_H
+
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <dali/public-api/common/dali-common.h>
+#include <dali/public-api/signals/dali-signal.h>
+
+namespace Dali
+{
+
+class TextureSet;
+
+namespace Toolkit
+{
+
+
+/**
+ * @brief Base class used to observe the upload status of a texture.
+ *
+ * Derived class must implement the UploadComplete method which is
+ * executed once the texture is ready to draw.
+ */
+class DALI_IMPORT_API TextureUploadObserver
+{
+public:
+
+ typedef Signal< void ( TextureUploadObserver* ) > DestructionSignalType; ///< Signal prototype for the Destruction Signal.
+
+ /**
+ * @brief Constructor.
+ */
+ TextureUploadObserver();
+
+ /**
+ * @brief Virtual destructor.
+ */
+ virtual ~TextureUploadObserver();
+
+ /**
+ * The action to be taken once the async load has finished and the upload to GPU is completed.
+ * This should be overridden by the deriving class.
+ *
+ * @param[in] loadSuccess True if the texture load was successful (i.e. the resource is available). If false, then the resource failed to load. In future, this will automatically upload a "broken" image.
+ * @param[in] textureSet The TextureSet containing the Texture
+ * @param[in] useAtlasing True if atlasing was used (note: this may be different to what was requested)
+ * @param[in] atlasRect If using atlasing, this is the rectangle within the atlas to use.
+ */
+ virtual void UploadComplete( bool loadSuccess, TextureSet textureSet, bool useAtlasing, const Vector4& atlasRect ) = 0;
+
+ /**
+ * @brief Returns the destruction signal.
+ * This is emitted when the observer is destroyed.
+ * This is used by the observer notifier to mark this observer as destroyed (IE. It no longer needs notifying).
+ */
+ DestructionSignalType& DestructionSignal();
+
+private:
+
+ DestructionSignalType mDestructionSignal; ///< The destruction signal emitted when the observer is destroyed.
+
+};
+
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_TEXTURE_UPLOAD_OBSERVER_H
return mAtlasManager;
}
+TextureManager& VisualFactoryCache::GetTextureManager()
+{
+ return mTextureManager;
+}
+
NPatchLoader& VisualFactoryCache::GetNPatchLoader()
{
return mNPatchLoader;
// INTERNAL INCLUDES
#include <dali-toolkit/internal/visuals/npatch-loader.h>
#include <dali-toolkit/internal/visuals/svg/svg-rasterize-thread.h>
+#include <dali-toolkit/internal/visuals/texture-manager.h>
namespace Dali
{
namespace Internal
{
-
class ImageAtlasManager;
+class NPatchLoader;
+class TextureManager;
+
typedef IntrusivePtr<ImageAtlasManager> ImageAtlasManagerPtr;
-class NPatchLoader;
/**
* Caches shaders and geometries. Owned by VisualFactory.
ImageAtlasManagerPtr GetAtlasManager();
/**
+ * Get the texture manager
+ * @return A reference to the texture manager
+ */
+ TextureManager& GetTextureManager();
+
+ /**
* Get the N-Patch texture cache.
* @return A reference to the N patch loader
*/
Shader mShader[SHADER_TYPE_MAX+1];
ImageAtlasManagerPtr mAtlasManager;
- NPatchLoader mNPatchLoader;
-
+ TextureManager mTextureManager;
+ NPatchLoader mNPatchLoader;
SvgRasterizeThread* mSvgRasterizeThread;
};
// INTERNAL INCLUDES
#include <dali-toolkit/internal/image-loader/async-image-loader-impl.h>
+#include <dali-toolkit/internal/visuals/visual-url.h>
namespace Dali
{
uint32_t AsyncImageLoader::Load( const std::string& url )
{
- return GetImplementation( *this ).Load( url, ImageDimensions(), FittingMode::DEFAULT, SamplingMode::BOX_THEN_LINEAR, true );
+ return GetImplementation( *this ).Load( Toolkit::Internal::VisualUrl(url), ImageDimensions(), FittingMode::DEFAULT, SamplingMode::BOX_THEN_LINEAR, true );
}
uint32_t AsyncImageLoader::Load( const std::string& url, ImageDimensions dimensions )
{
- return GetImplementation( *this ).Load( url, dimensions, FittingMode::DEFAULT, SamplingMode::BOX_THEN_LINEAR, true );
+ return GetImplementation( *this ).Load( Toolkit::Internal::VisualUrl(url), dimensions, FittingMode::DEFAULT, SamplingMode::BOX_THEN_LINEAR, true );
}
uint32_t AsyncImageLoader::Load( const std::string& url,
SamplingMode::Type samplingMode,
bool orientationCorrection )
{
- return GetImplementation(*this).Load( url, dimensions, fittingMode, samplingMode, orientationCorrection );
+ return GetImplementation(*this).Load( Toolkit::Internal::VisualUrl(url), dimensions, fittingMode, samplingMode, orientationCorrection );
}
bool AsyncImageLoader::Cancel( uint32_t loadingTaskId )