From: David Steele Date: Fri, 16 Dec 2016 15:08:44 +0000 (-0800) Subject: Merge "Fix SVACE error in KeyboardFocusManager" into devel/master X-Git-Tag: dali_1.2.20~16 X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=commitdiff_plain;h=80ab4492a0df45c146d9ad97daef3c522bb02e2c;hp=0427f0733297887a3402377de6a083de0e32ce71 Merge "Fix SVACE error in KeyboardFocusManager" into devel/master --- diff --git a/automated-tests/resources/anim.gif b/automated-tests/resources/anim.gif new file mode 100644 index 0000000..f66f076 Binary files /dev/null and b/automated-tests/resources/anim.gif differ diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-VisualFactoryResolveUrl.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-VisualFactoryResolveUrl.cpp index f859b74..8235355 100644 --- a/automated-tests/src/dali-toolkit-internal/utc-Dali-VisualFactoryResolveUrl.cpp +++ b/automated-tests/src/dali-toolkit-internal/utc-Dali-VisualFactoryResolveUrl.cpp @@ -30,8 +30,6 @@ int UtcDaliResolveUrlRegularImage(void) DALI_TEST_EQUALS( UrlType::REGULAR_IMAGE, ResolveUrlType("foobar.jpeg"), TEST_LOCATION ); - DALI_TEST_EQUALS( UrlType::REGULAR_IMAGE, ResolveUrlType("foobar.gif"), TEST_LOCATION ); - DALI_TEST_EQUALS( UrlType::REGULAR_IMAGE, ResolveUrlType("foobar.PNG"), TEST_LOCATION ); DALI_TEST_EQUALS( UrlType::REGULAR_IMAGE, ResolveUrlType("foobar.Png123"), TEST_LOCATION ); @@ -78,8 +76,6 @@ int UtcDaliResolveUrlNPatch(void) { tet_infoline( "UtcDaliResolveUrl N_PATCH" ); - DALI_TEST_EQUALS( UrlType::N_PATCH, ResolveUrlType("foobar.9.gif"), TEST_LOCATION ); - DALI_TEST_EQUALS( UrlType::N_PATCH, ResolveUrlType("foobar.#.png"), TEST_LOCATION ); DALI_TEST_EQUALS( UrlType::N_PATCH, ResolveUrlType("foobar.9.9.bmp"), TEST_LOCATION ); @@ -94,3 +90,26 @@ int UtcDaliResolveUrlNPatch(void) END_TEST; } + +int UtcDaliResolveUrlGif(void) +{ + tet_infoline( "UtcDaliResolveUrl GIF" ); + + DALI_TEST_EQUALS( UrlType::GIF, ResolveUrlType("foobar.gif"), TEST_LOCATION ); + + DALI_TEST_EQUALS( UrlType::GIF, ResolveUrlType("foobar.gif.gif"), TEST_LOCATION ); + + DALI_TEST_EQUALS( UrlType::GIF, ResolveUrlType("foobar.giF"), TEST_LOCATION ); + + DALI_TEST_EQUALS( UrlType::GIF, ResolveUrlType("foobar.GIF"), TEST_LOCATION ); + + DALI_TEST_EQUALS( UrlType::GIF, ResolveUrlType(".GiF"), TEST_LOCATION ); + + // GIFs aren't N-patch + DALI_TEST_EQUALS( UrlType::GIF, ResolveUrlType("foobar.9.gif"), TEST_LOCATION ); + + DALI_TEST_EQUALS( UrlType::REGULAR_IMAGE, ResolveUrlType("gif.png"), TEST_LOCATION ); + DALI_TEST_EQUALS( UrlType::REGULAR_IMAGE, ResolveUrlType("gif.gif1"), TEST_LOCATION ); + + END_TEST; +} diff --git a/automated-tests/src/dali-toolkit/utc-Dali-ImageAtlas.cpp b/automated-tests/src/dali-toolkit/utc-Dali-ImageAtlas.cpp index 0bee5e5..17b4432 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-ImageAtlas.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-ImageAtlas.cpp @@ -40,14 +40,35 @@ static const char* gImageNonExist = "non-exist.jpg"; const int RENDER_FRAME_INTERVAL = 16; ///< Duration of each frame in ms. (at approx 60FPS) +PixelData CreatePixelData( unsigned int width, unsigned int height ) +{ + unsigned int bufferSize = width*height*Pixel::GetBytesPerPixel( Pixel::RGBA8888 ); + + unsigned char* buffer= reinterpret_cast( malloc( bufferSize ) ); + PixelData pixelData = PixelData::New( buffer, bufferSize, width, height, Pixel::RGBA8888, PixelData::FREE ); + + return pixelData; +} + Rect TextureCoordinateToPixelArea( const Vector4& textureCoordinate, float size ) { Vector4 temp = textureCoordinate * size; Rect pixelArea; pixelArea.x = static_cast( temp.x ); pixelArea.y = static_cast( temp.y ); - pixelArea.width = static_cast( temp.z-temp.x+1.f ); - pixelArea.height = static_cast( temp.w-temp.y+1.f ); + pixelArea.width = static_cast( temp.z-temp.x+1.01f ); + pixelArea.height = static_cast( temp.w-temp.y+1.01f ); + + return pixelArea; +} + +Rect TextureCoordinateToPixelArea( const Vector4& textureCoordinate, float width, float height ) +{ + Rect pixelArea; + pixelArea.x = static_cast( textureCoordinate.x*width ); + pixelArea.y = static_cast( textureCoordinate.y*height); + pixelArea.width = static_cast( (textureCoordinate.z-textureCoordinate.x)*width+1.01f ); + pixelArea.height = static_cast( (textureCoordinate.w-textureCoordinate.y)*height+1.01f ); return pixelArea; } @@ -434,3 +455,56 @@ int UtcDaliImageAtlasImageView(void) END_TEST; } + +int UtcDaliImageAtlasPackToAtlas(void) +{ + ToolkitTestApplication application; + + std::vector pixelDataContainer; + pixelDataContainer.push_back( CreatePixelData( 20, 30 ) ); + pixelDataContainer.push_back( CreatePixelData( 10, 10 ) ); + pixelDataContainer.push_back( CreatePixelData( 45, 30 ) ); + pixelDataContainer.push_back( CreatePixelData( 20, 20 ) ); + + Dali::Vector textureRects; + Texture texture = ImageAtlas::PackToAtlas( pixelDataContainer, textureRects ); + + // -------------- + // | | + // | 45*30 | +// | | +// -------------- +// | 20 | | 20*20 +// | * |____| +// | 30 | | 10*10 +// -------- + + DALI_TEST_EQUALS( texture.GetWidth(), 45, TEST_LOCATION ); + DALI_TEST_EQUALS( texture.GetHeight(), 60, TEST_LOCATION ); + + Rect pixelArea = TextureCoordinateToPixelArea(textureRects[0], texture.GetWidth(), texture.GetHeight()); + DALI_TEST_EQUALS( pixelArea.x, 0, TEST_LOCATION ); + DALI_TEST_EQUALS( pixelArea.y, 30, TEST_LOCATION ); + DALI_TEST_EQUALS( pixelArea.width, 20, TEST_LOCATION ); + DALI_TEST_EQUALS( pixelArea.height, 30, TEST_LOCATION ); + + pixelArea = TextureCoordinateToPixelArea(textureRects[1], texture.GetWidth(), texture.GetHeight()); + DALI_TEST_EQUALS( pixelArea.x, 20, TEST_LOCATION ); + DALI_TEST_EQUALS( pixelArea.y, 50, TEST_LOCATION ); + DALI_TEST_EQUALS( pixelArea.width, 10, TEST_LOCATION ); + DALI_TEST_EQUALS( pixelArea.height, 10, TEST_LOCATION ); + + pixelArea = TextureCoordinateToPixelArea(textureRects[2], texture.GetWidth(), texture.GetHeight()); + DALI_TEST_EQUALS( pixelArea.x, 0, TEST_LOCATION ); + DALI_TEST_EQUALS( pixelArea.y, 0, TEST_LOCATION ); + DALI_TEST_EQUALS( pixelArea.width, 45, TEST_LOCATION ); + DALI_TEST_EQUALS( pixelArea.height, 30, TEST_LOCATION ); + + pixelArea = TextureCoordinateToPixelArea(textureRects[3], texture.GetWidth(), texture.GetHeight()); + DALI_TEST_EQUALS( pixelArea.x, 20, TEST_LOCATION ); + DALI_TEST_EQUALS( pixelArea.y, 30, TEST_LOCATION ); + DALI_TEST_EQUALS( pixelArea.width, 20, TEST_LOCATION ); + DALI_TEST_EQUALS( pixelArea.height, 20, TEST_LOCATION ); + + END_TEST; +} diff --git a/automated-tests/src/dali-toolkit/utc-Dali-Visual.cpp b/automated-tests/src/dali-toolkit/utc-Dali-Visual.cpp index fae713a..4885bc2 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-Visual.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-Visual.cpp @@ -38,6 +38,7 @@ namespace const char* TEST_IMAGE_FILE_NAME = TEST_RESOURCE_DIR "/gallery-small-1.jpg"; const char* TEST_NPATCH_FILE_NAME = "gallery_image_01.9.jpg"; const char* TEST_SVG_FILE_NAME = TEST_RESOURCE_DIR "/svg1.svg"; +const char* TEST_GIF_FILE_NAME = TEST_RESOURCE_DIR "/anim.gif"; const char* TEST_OBJ_FILE_NAME = TEST_RESOURCE_DIR "/Cube.obj"; const char* TEST_MTL_FILE_NAME = TEST_RESOURCE_DIR "/ToyRobot-Metal.mtl"; const char* TEST_RESOURCE_LOCATION = TEST_RESOURCE_DIR "/"; @@ -292,6 +293,14 @@ int UtcDaliVisualSize(void) const float height = textVisual.GetHeightForWidth( 40.f ); DALI_TEST_EQUALS( height, 40.f, Math::MACHINE_EPSILON_1000, TEST_LOCATION ); + //AnimatedImageVisual + Visual::Base animatedImageVisual = factory.CreateVisual( TEST_GIF_FILE_NAME, ImageDimensions() ); + animatedImageVisual.SetTransformAndSize(DefaultTransform(), controlSize ); + animatedImageVisual.GetNaturalSize(naturalSize); + // TEST_GIF_FILE: anim.gif + // resolution: 50*50, frame count: 4, frame delay: 0.2 second for each frame + DALI_TEST_EQUALS( naturalSize, Vector2(50.f, 50.f), TEST_LOCATION ); + END_TEST; } @@ -990,6 +999,45 @@ int UtcDaliVisualGetPropertyMap10(void) END_TEST; } +int UtcDaliVisualGetPropertyMap11(void) +{ + ToolkitTestApplication application; + tet_infoline( "UtcDaliVisualGetPropertyMap7: AnimatedImageVisual" ); + + // request SvgVisual with a property map + VisualFactory factory = VisualFactory::Get(); + Property::Map propertyMap; + Visual::Base svgVisual = factory.CreateVisual( Property::Map() + .Add( Visual::Property::TYPE, Visual::IMAGE ) + .Add( ImageVisual::Property::URL, TEST_GIF_FILE_NAME ) ); + + Property::Map resultMap; + svgVisual.CreatePropertyMap( resultMap ); + // check the property values from the returned map from a visual + Property::Value* value = resultMap.Find( Visual::Property::TYPE, Property::INTEGER ); + DALI_TEST_CHECK( value ); + DALI_TEST_CHECK( value->Get() == Visual::IMAGE ); + + value = resultMap.Find( ImageVisual::Property::URL, Property::STRING ); + DALI_TEST_CHECK( value ); + DALI_TEST_CHECK( value->Get() == TEST_GIF_FILE_NAME ); + + // request SvgVisual with an URL + Visual::Base svgVisual2 = factory.CreateVisual( TEST_GIF_FILE_NAME, ImageDimensions() ); + resultMap.Clear(); + svgVisual2.CreatePropertyMap( resultMap ); + // check the property values from the returned map from a visual + value = resultMap.Find( Visual::Property::TYPE, Property::INTEGER ); + DALI_TEST_CHECK( value ); + DALI_TEST_CHECK( value->Get() == Visual::IMAGE ); + + value = resultMap.Find( ImageVisual::Property::URL, Property::STRING ); + DALI_TEST_CHECK( value ); + DALI_TEST_CHECK( value->Get() == TEST_GIF_FILE_NAME ); + + END_TEST; +} + int UtcDaliVisualGetPropertyMapBatchImageVisualNoAtlas(void) { ToolkitTestApplication application; diff --git a/automated-tests/src/dali-toolkit/utc-Dali-VisualFactory.cpp b/automated-tests/src/dali-toolkit/utc-Dali-VisualFactory.cpp index b186ea4..0e9c014 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-VisualFactory.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-VisualFactory.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -44,6 +45,9 @@ const char* TEST_MTL_FILE_NAME = TEST_RESOURCE_DIR "/ToyRobot-Metal.mtl"; const char* TEST_SIMPLE_OBJ_FILE_NAME = TEST_RESOURCE_DIR "/Cube-Points-Only.obj"; const char* TEST_SIMPLE_MTL_FILE_NAME = TEST_RESOURCE_DIR "/ToyRobot-Metal-Simple.mtl"; +// resolution: 50*50, frame count: 4, frame delay: 0.2 second for each frame +const char* TEST_GIF_FILE_NAME = TEST_RESOURCE_DIR "/anim.gif"; + // resolution: 34*34, pixel format: RGBA8888 static const char* gImage_34_RGBA = TEST_RESOURCE_DIR "/icon-edit.png"; // resolution: 600*600, pixel format: RGB888 @@ -2051,3 +2055,82 @@ int UtcDaliVisualFactoryGetBatchImageVisual3(void) END_TEST; } + +int UtcDaliVisualFactoryGetAnimatedImageVisual(void) +{ + ToolkitTestApplication application; + tet_infoline( "UtcDaliVisualFactoryGetAnimatedImageVisual: Request animated image visual with a gif url" ); + + VisualFactory factory = VisualFactory::Get(); + Visual::Base visual = factory.CreateVisual( TEST_GIF_FILE_NAME, ImageDimensions() ); + DALI_TEST_CHECK( visual ); + + TestGlAbstraction& gl = application.GetGlAbstraction(); + TraceCallStack& textureTrace = gl.GetTextureTrace(); + textureTrace.Enable(true); + + DummyControl actor = DummyControl::New(); + DummyControlImpl& dummyImpl = static_cast(actor.GetImplementation()); + dummyImpl.RegisterVisual( Control::CONTROL_PROPERTY_END_INDEX + 1, visual ); + Stage::GetCurrent().Add( actor ); + + application.SendNotification(); + application.Render(); + + // renderer is added to actor + DALI_TEST_CHECK( actor.GetRendererCount() == 1u ); + + // test the uniforms which used to handle the atlas rect + // the four frames should be located inside atlas as follows: atlas size 100*100 + // ------------- + // | | | + // | 0 | 1 | + // ------------- + // | | | + // | 2 | 3 | + // ------------- + + Renderer renderer = actor.GetRendererAt( 0u ); + DALI_TEST_CHECK( renderer ); + + Property::Value atlasRectValue = renderer.GetProperty( renderer.GetPropertyIndex( "uAtlasRect" ) ); + // take into consideration the half pixel correction + DALI_TEST_EQUALS( atlasRectValue.Get(), Vector4(0.5f, 0.5f, 49.5f, 49.5f)/100.f, Math::MACHINE_EPSILON_100, TEST_LOCATION ); + + // waiting for the resource uploading + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION ); + + // Force the timer used by the animatedImageVisual to tick, + Dali::Timer timer = Timer::New( 0 ); + timer.MockEmitSignal(); + application.SendNotification(); + application.Render(); + atlasRectValue = renderer.GetProperty( renderer.GetPropertyIndex( "uAtlasRect" ) ); + // take into consideration the half pixel correction + DALI_TEST_EQUALS( atlasRectValue.Get(), Vector4(50.5f, 0.5f, 99.5f, 49.5f)/100.f, Math::MACHINE_EPSILON_100, TEST_LOCATION ); + + // Force the timer used by the animatedImageVisual to tick, + timer.MockEmitSignal(); + application.SendNotification(); + application.Render(); + atlasRectValue = renderer.GetProperty( renderer.GetPropertyIndex( "uAtlasRect" ) ); + // take into consideration the half pixel correction + DALI_TEST_EQUALS( atlasRectValue.Get(), Vector4(0.5f, 50.5f, 49.5f, 99.5f)/100.f, Math::MACHINE_EPSILON_100, TEST_LOCATION ); + + // Force the timer used by the animatedImageVisual to tick, + timer.MockEmitSignal(); + application.SendNotification(); + application.Render(); + atlasRectValue = renderer.GetProperty( renderer.GetPropertyIndex( "uAtlasRect" ) ); + // take into consideration the half pixel correction + DALI_TEST_EQUALS( atlasRectValue.Get(), Vector4(50.5f, 50.5f, 99.5f, 99.5f)/100.f, Math::MACHINE_EPSILON_100, TEST_LOCATION ); + + // Test SetOffStage(). + actor.Unparent(); + DALI_TEST_CHECK( actor.GetRendererCount() == 0u ); + + END_TEST; +} diff --git a/dali-toolkit/devel-api/image-loader/image-atlas.cpp b/dali-toolkit/devel-api/image-loader/image-atlas.cpp index fd6825e..84903b3 100644 --- a/dali-toolkit/devel-api/image-loader/image-atlas.cpp +++ b/dali-toolkit/devel-api/image-loader/image-atlas.cpp @@ -35,6 +35,11 @@ ImageAtlas::~ImageAtlas() { } +Texture ImageAtlas::PackToAtlas( const std::vector& pixelData, Dali::Vector& textureRects ) +{ + return Internal::ImageAtlas::PackToAtlas( pixelData, textureRects ); +} + ImageAtlas::ImageAtlas(Internal::ImageAtlas* internal) : BaseHandle( internal ) { diff --git a/dali-toolkit/devel-api/image-loader/image-atlas.h b/dali-toolkit/devel-api/image-loader/image-atlas.h index 98796bd..a0305fd 100644 --- a/dali-toolkit/devel-api/image-loader/image-atlas.h +++ b/dali-toolkit/devel-api/image-loader/image-atlas.h @@ -20,6 +20,7 @@ // EXTERNAL INCLUDES #include #include +#include #include #include #include @@ -34,6 +35,7 @@ namespace Dali namespace Toolkit { + namespace Internal DALI_INTERNAL { class ImageAtlas; @@ -54,6 +56,14 @@ public: public: /** + * @brief Pack a group of pixel data into atlas. + * @param[in] pixelData The group of the pixel data to be packed into the atlas. + * @param[out] textureRects The list of texture areas where each frame is located inside the atlas. + * @return The atlas texture. + */ + static Texture PackToAtlas( const std::vector& pixelData, Dali::Vector& textureRects ); + + /** * @brief Create a new ImageAtlas. * * @param [in] width The atlas width in pixels. diff --git a/dali-toolkit/internal/controls/table-view/table-view-impl.cpp b/dali-toolkit/internal/controls/table-view/table-view-impl.cpp index 4a655aa..e3b0334 100644 --- a/dali-toolkit/internal/controls/table-view/table-view-impl.cpp +++ b/dali-toolkit/internal/controls/table-view/table-view-impl.cpp @@ -1319,51 +1319,74 @@ Actor TableView::GetNextKeyboardFocusableActor(Actor currentFocusedActor, Toolki int numberOfColumns = GetColumns(); int numberOfRows = GetRows(); + bool lastCell = false; + Actor nextValidActor; + switch ( direction ) { case Toolkit::Control::KeyboardFocus::LEFT: { - if(--currentColumn < 0) + do { - currentColumn = numberOfColumns - 1; - if(--currentRow < 0) + if(--currentColumn < 0) { - currentRow = loopEnabled ? numberOfRows - 1 : 0; - focusLost = (currentRow == 0); + currentColumn = numberOfColumns - 1; + if(--currentRow < 0) + { + lastCell = true; + currentRow = loopEnabled ? numberOfRows - 1 : 0; + focusLost = (currentRow == 0); + } } - } + nextValidActor = GetChildAt(Toolkit::TableView::CellPosition(currentRow, currentColumn)); + } while ( !nextValidActor && !lastCell ); break; } case Toolkit::Control::KeyboardFocus::RIGHT: { - if(++currentColumn > numberOfColumns - 1) + do { - currentColumn = 0; - if(++currentRow > numberOfRows - 1) + if(++currentColumn > numberOfColumns - 1) { - currentRow = loopEnabled ? 0 : numberOfRows - 1; - focusLost = (currentRow == numberOfRows - 1); + currentColumn = 0; + if(++currentRow > numberOfRows - 1) + { + lastCell = true; + currentRow = loopEnabled ? 0 : numberOfRows - 1; + focusLost = (currentRow == numberOfRows - 1); + } } - } + nextValidActor = GetChildAt(Toolkit::TableView::CellPosition(currentRow, currentColumn)); + } while ( !nextValidActor && !lastCell ); break; } case Toolkit::Control::KeyboardFocus::UP: { - if(--currentRow < 0) + do { - currentRow = loopEnabled ? numberOfRows - 1 : 0; - focusLost = (currentRow == 0); - } + if(--currentRow < 0) + { + lastCell = true; + currentRow = loopEnabled ? numberOfRows - 1 : 0; + focusLost = (currentRow == 0); + } + nextValidActor = GetChildAt(Toolkit::TableView::CellPosition(currentRow, currentColumn)); + } while ( !nextValidActor && !lastCell ); break; } case Toolkit::Control::KeyboardFocus::DOWN: { - if(++currentRow > numberOfRows - 1) + do { - currentRow = loopEnabled ? 0 : numberOfRows - 1; - focusLost = (currentRow == numberOfRows - 1); - } + if(++currentRow > numberOfRows - 1) + { + lastCell = true; + currentRow = loopEnabled ? 0 : numberOfRows - 1; + focusLost = (currentRow == numberOfRows - 1); + } + nextValidActor = GetChildAt(Toolkit::TableView::CellPosition(currentRow, currentColumn)); + } while ( !nextValidActor && !lastCell ); break; } } diff --git a/dali-toolkit/internal/file.list b/dali-toolkit/internal/file.list index 7fa3af7..a4f49d9 100644 --- a/dali-toolkit/internal/file.list +++ b/dali-toolkit/internal/file.list @@ -17,6 +17,7 @@ toolkit_src_files = \ $(toolkit_src_dir)/visuals/visual-factory-cache.cpp \ $(toolkit_src_dir)/visuals/visual-factory-impl.cpp \ $(toolkit_src_dir)/visuals/visual-string-constants.cpp \ + $(toolkit_src_dir)/visuals/animated-image/animated-image-visual.cpp \ $(toolkit_src_dir)/visuals/border/border-visual.cpp \ $(toolkit_src_dir)/visuals/color/color-visual.cpp \ $(toolkit_src_dir)/visuals/gradient/gradient.cpp \ diff --git a/dali-toolkit/internal/image-loader/atlas-packer.cpp b/dali-toolkit/internal/image-loader/atlas-packer.cpp index f452399..4212188 100644 --- a/dali-toolkit/internal/image-loader/atlas-packer.cpp +++ b/dali-toolkit/internal/image-loader/atlas-packer.cpp @@ -20,6 +20,7 @@ // EXTERNAL HEADER #include // For abs() +#include namespace Dali { @@ -38,6 +39,18 @@ bool ApproximatelyEqual( uint32_t a, uint32_t b ) return abs( a-b ) <= 1; } +uint16_t MaxDimension( const Uint16Pair& dimensions ) +{ + return dimensions.GetWidth() >= dimensions.GetHeight() ? dimensions.GetWidth() : dimensions.GetHeight(); +} + +void Swap( Uint16Pair& first, Uint16Pair& second ) +{ + Uint16Pair temp = first; + first = second; + second = temp; +} + } AtlasPacker::Node::Node( Node* parent, SizeType x, SizeType y, SizeType width, SizeType height ) @@ -195,6 +208,103 @@ void AtlasPacker::DeleteNode( Node *node ) } } +Uint16Pair AtlasPacker::GroupPack( const Dali::Vector& blockSizes, Dali::Vector& packPositions ) +{ + uint16_t count = blockSizes.Count(); + packPositions.Resize( count ); + + // Sort the blocks according to its maximum dimension. The bigger blocks are packed first. + Dali::Vector packOrder; + packOrder.Resize( count ); + for( uint16_t i = 0; i < count; i++ ) + { + packOrder[i].SetX( MaxDimension( blockSizes[i] ) ); + packOrder[i].SetY( i ); + } + for( uint16_t i = 0; i < count-1; i++ ) + for( uint16_t j = 0; j < count-i-1; j++ ) + { + if( packOrder[j].GetX() < packOrder[j+1].GetX() ) + { + Swap( packOrder[j], packOrder[j+1] ); + } + } + + int index = packOrder[0].GetY(); + AtlasPacker packer( blockSizes[index].GetWidth(), blockSizes[index].GetHeight() ); + + SizeType packPositionX, packPositionY; + // pack the blocks one by one with descending size, grows as necessary to accommodate each subsequent block. + for( uint16_t i = 0; i < count; i++ ) + { + index = packOrder[i].GetY(); + packer.GrowPack( blockSizes[index].GetWidth(), blockSizes[index].GetHeight(), + packPositionX, packPositionY ); + packPositions[index].SetX( packPositionX ); + packPositions[index].SetY( packPositionY ); + } + + return Uint16Pair( packer.mRoot->rectArea.width, packer.mRoot->rectArea.height ); +} + +void AtlasPacker::GrowPack( SizeType blockWidth, SizeType blockHeight, + SizeType& packPositionX, SizeType& packPositionY ) +{ + Node* firstFit = InsertNode( mRoot, blockWidth, blockHeight ); + if( firstFit == NULL ) + { + // Could fit in the current left space, grow the partition tree to get more space. + GrowNode( blockWidth, blockHeight ); + firstFit = InsertNode( mRoot->child[1], blockWidth, blockHeight ); + } + + if( firstFit != NULL ) + { + firstFit->occupied = true; + packPositionX = firstFit->rectArea.x; + packPositionY = firstFit->rectArea.y; + } +} + +void AtlasPacker::GrowNode( SizeType blockWidth, SizeType blockHeight ) +{ + // Attempts to maintain a roughly square ratio when choosing the growing direction: right or down + bool canGrowRight = blockWidth <= mRoot->rectArea.width; + bool canGrowDown = blockHeight <= mRoot->rectArea.height; + + bool shouldGrowRight = canGrowRight && mRoot->rectArea.height >= mRoot->rectArea.width+blockWidth; + bool shouldGrowDown = canGrowDown && mRoot->rectArea.width >= mRoot->rectArea.height+blockHeight; + + if( canGrowRight && canGrowRight ) + { + shouldGrowRight = mRoot->rectArea.width+blockWidth <= mRoot->rectArea.height+blockHeight; + shouldGrowDown = !shouldGrowRight; + } + + if( shouldGrowRight || ( canGrowRight && !shouldGrowDown ) ) + { + Node* newRoot = new Node( NULL, 0u, 0u, mRoot->rectArea.width+blockWidth, mRoot->rectArea.height ); + newRoot->occupied = true; + newRoot->child[0] = mRoot; + newRoot->child[1] = new Node( newRoot, mRoot->rectArea.width, 0u, blockWidth, mRoot->rectArea.height ); + + mRoot = newRoot; + } + else if( shouldGrowDown || ( canGrowDown && !shouldGrowRight ) ) + { + Node* newRoot = new Node( NULL, 0u, 0u, mRoot->rectArea.width, mRoot->rectArea.height+blockHeight ); + newRoot->occupied = true; + newRoot->child[0] = mRoot; + newRoot->child[1] = new Node( newRoot, 0u, mRoot->rectArea.height, mRoot->rectArea.width, blockHeight ); + + mRoot = newRoot; + } + else + { + DALI_LOG_ERROR( " Atlas Packer failed to grow: make sure the packing order is sorted with the block size to avoid this happening"); + } +} + } // namespace Internal } // namespace Toolkit diff --git a/dali-toolkit/internal/image-loader/atlas-packer.h b/dali-toolkit/internal/image-loader/atlas-packer.h index bab993f..2d6c95b 100644 --- a/dali-toolkit/internal/image-loader/atlas-packer.h +++ b/dali-toolkit/internal/image-loader/atlas-packer.h @@ -18,7 +18,9 @@ */ #include +#include #include +#include namespace Dali { @@ -99,6 +101,14 @@ public: */ unsigned int GetAvailableArea() const; + /** + * Pack a group of blocks with different sizes, calculate the required packing size and the position of each block. + * @param[in] blockSizes The size list of the blocks . + * @param[out] packPositions The packing position of each block. + * @return The required size to accommodate all the blocks. + */ + static Uint16Pair GroupPack( const Dali::Vector& blockSizes, Dali::Vector& packPositions ); + private: /* @@ -146,11 +156,30 @@ private: */ void DeleteNode( Node* node ); + /** + * Pack a block into the atlas. If there is no enough room, grow the partition tree. + * + * @param[in] blockWidth The width of the block to pack. + * @param[in] blockHeight The height of the block to pack. + * @param[out] packPositionX The x coordinate of the position to pack the block. + * @param[out] packPositionY The y coordinate of the position to pack the block. + */ + void GrowPack( SizeType blockWidth, SizeType blockHeight, + SizeType& packPositionX, SizeType& packPositionY ); + + /** + * Add extra node into the partition tree to accommodate the given block. + * + * @param[in] blockWidth The width of the block to pack. + * @param[in] blockHeight The height of the block to pack. + */ + void GrowNode( SizeType blockWidth, SizeType blockHeight ); + // Undefined - AtlasPacker( const AtlasPacker& imageAtlas); + AtlasPacker( const AtlasPacker& atlasPacker); // Undefined - AtlasPacker& operator=( const AtlasPacker& imageAtlas ); + AtlasPacker& operator=( const AtlasPacker& atlasPacker ); private: diff --git a/dali-toolkit/internal/image-loader/image-atlas-impl.cpp b/dali-toolkit/internal/image-loader/image-atlas-impl.cpp index bdd2780..da8fe90 100644 --- a/dali-toolkit/internal/image-loader/image-atlas-impl.cpp +++ b/dali-toolkit/internal/image-loader/image-atlas-impl.cpp @@ -34,6 +34,49 @@ namespace Toolkit namespace Internal { +Texture ImageAtlas::PackToAtlas( const std::vector& pixelData, Dali::Vector& textureRects ) +{ + // Record each block size + Dali::Vector blockSizes; + SizeType count = pixelData.size(); + for( SizeType index = 0; index < count; index++ ) + { + blockSizes.PushBack( ImageDimensions( pixelData[index].GetWidth(), pixelData[index].GetHeight() ) ); + } + + // Ask atlasPacker for packing position of each block + Dali::Vector packPositions; + ImageDimensions atlasSize = AtlasPacker::GroupPack( blockSizes, packPositions ); + + // Prepare for outout texture rect array + textureRects.Clear(); + textureRects.Resize( count ); + + // create the texture for uploading the multiple pixel data + Texture atlasTexture = Texture::New( Dali::TextureType::TEXTURE_2D, Pixel::RGBA8888, atlasSize.GetWidth(), atlasSize.GetHeight() ); + + float atlasWidth = static_cast( atlasTexture.GetWidth() ); + float atlasHeight = static_cast( atlasTexture.GetHeight() ); + int packPositionX, packPositionY; + // Upload the pixel data one by one to its packing position, and record the texture rects + for( SizeType index = 0; index < count; index++ ) + { + packPositionX = packPositions[index].GetX(); + packPositionY = packPositions[index].GetY(); + atlasTexture.Upload( pixelData[index], 0u, 0u, + packPositionX, packPositionY, + pixelData[index].GetWidth(), pixelData[index].GetHeight() ); + + // Apply the half pixel correction to avoid the color bleeding between neighbour blocks + textureRects[index].x = ( static_cast( packPositionX ) +0.5f ) / atlasWidth; // left + textureRects[index].y = ( static_cast( packPositionY ) +0.5f ) / atlasHeight; // right + textureRects[index].z = ( static_cast( packPositionX + pixelData[index].GetWidth() )-0.5f ) / atlasWidth; // right + textureRects[index].w = ( static_cast( packPositionY + pixelData[index].GetHeight() )-0.5f ) / atlasHeight;// bottom + } + + return atlasTexture; +} + ImageAtlas::ImageAtlas( SizeType width, SizeType height, Pixel::Format pixelFormat ) : mAtlas( Texture::New( Dali::TextureType::TEXTURE_2D, pixelFormat, width, height ) ), mPacker( width, height ), diff --git a/dali-toolkit/internal/image-loader/image-atlas-impl.h b/dali-toolkit/internal/image-loader/image-atlas-impl.h index 4f735ef..2980627 100644 --- a/dali-toolkit/internal/image-loader/image-atlas-impl.h +++ b/dali-toolkit/internal/image-loader/image-atlas-impl.h @@ -47,6 +47,11 @@ public: typedef Toolkit::ImageAtlas::SizeType SizeType; /** + * @copydoc ImageAtlas::PackToAtlas( const std::vector&, Dali::Vector& ) + */ + static Texture PackToAtlas( const std::vector& pixelData, Dali::Vector& textureRects ); + + /** * Constructor * @param [in] width The atlas width in pixels. * @param [in] height The atlas height in pixels. diff --git a/dali-toolkit/internal/visuals/animated-image/animated-image-visual.cpp b/dali-toolkit/internal/visuals/animated-image/animated-image-visual.cpp new file mode 100644 index 0000000..5a3a154 --- /dev/null +++ b/dali-toolkit/internal/visuals/animated-image/animated-image-visual.cpp @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2016 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 "animated-image-visual.h" + +// EXTERNAL INCLUDES +#include + +// INTERNAL INCLUDES +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Dali +{ + +namespace Toolkit +{ + +namespace Internal +{ + +AnimatedImageVisualPtr AnimatedImageVisual::New( VisualFactoryCache& factoryCache, const std::string& imageUrl, const Property::Map& properties ) +{ + AnimatedImageVisual* visual = new AnimatedImageVisual( factoryCache ); + visual->mImageUrl = imageUrl; + visual->SetProperties( properties ); + + return visual; +} + +AnimatedImageVisualPtr AnimatedImageVisual::New( VisualFactoryCache& factoryCache, const std::string& imageUrl ) +{ + AnimatedImageVisual* visual = new AnimatedImageVisual( factoryCache ); + visual->mImageUrl = imageUrl; + + return visual; +} + +AnimatedImageVisual::AnimatedImageVisual( VisualFactoryCache& factoryCache ) +: Visual::Base( factoryCache ), + mFrameDelayTimer(), + mImageUrl(), + mImageSize(), + mCurrentFrameIndex( 0 ) +{} + +AnimatedImageVisual::~AnimatedImageVisual() +{ +} + +void AnimatedImageVisual::GetNaturalSize( Vector2& naturalSize ) +{ + if( mImageSize.GetWidth() == 0 && mImageSize.GetHeight() == 0) + { + mImageSize = Dali::GetGifImageSize( mImageUrl ); + } + + naturalSize.width = mImageSize.GetWidth(); + naturalSize.height = mImageSize.GetHeight(); +} + +void AnimatedImageVisual::DoCreatePropertyMap( Property::Map& map ) const +{ + map.Clear(); + map.Insert( Toolkit::DevelVisual::Property::TYPE, Toolkit::Visual::IMAGE ); + if( !mImageUrl.empty() ) + { + map.Insert( Toolkit::ImageVisual::Property::URL, mImageUrl ); + } +} + +void AnimatedImageVisual::DoSetProperties( const Property::Map& propertyMap ) +{ + // url already passed in from constructor +} + +void AnimatedImageVisual::DoSetOnStage( Actor& actor ) +{ + Texture texture = PrepareAnimatedImage(); + if( texture ) // if the image loading is successful + { + Shader shader = ImageVisual::GetImageShader( mFactoryCache, true, true ); + Geometry geometry = mFactoryCache.GetGeometry( VisualFactoryCache::QUAD_GEOMETRY ); + TextureSet textureSet = TextureSet::New(); + mImpl->mRenderer = Renderer::New( geometry, shader ); + mImpl->mRenderer.SetTextures( textureSet ); + textureSet.SetTexture( 0u, PrepareAnimatedImage() ); + mImpl->mRenderer.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, mTextureRectContainer[0] ); + + // Register transform properties + mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT ); + + mCurrentFrameIndex = 0; + if( mFrameDelayContainer.Count() > 1 ) + { + mFrameDelayTimer = Timer::New( mFrameDelayContainer[0] ); + mFrameDelayTimer.TickSignal().Connect( this, &AnimatedImageVisual::DisplayNextFrame ); + mFrameDelayTimer.Start(); + } + + actor.AddRenderer( mImpl->mRenderer ); + } +} + +void AnimatedImageVisual::DoSetOffStage( Actor& actor ) +{ + if( !mImpl->mRenderer ) + { + return; + } + + if( mFrameDelayTimer ) + { + mFrameDelayTimer.Stop(); + mFrameDelayTimer.Reset(); + } + + mTextureRectContainer.Clear(); + mFrameDelayContainer.Clear(); + + actor.RemoveRenderer( mImpl->mRenderer ); + mImpl->mRenderer.Reset(); +} + +void AnimatedImageVisual::OnSetTransform() +{ + if( mImpl->mRenderer ) + { + mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT ); + } +} + +Texture AnimatedImageVisual::PrepareAnimatedImage() +{ + // load from image file + std::vector pixelDataList; + if( Dali::LoadAnimatedGifFromFile( mImageUrl.c_str() , pixelDataList, mFrameDelayContainer ) ) + { + mImageSize.SetWidth( pixelDataList[0].GetWidth() ); + mImageSize.SetHeight( pixelDataList[0].GetHeight() ); + + return Toolkit::ImageAtlas::PackToAtlas( pixelDataList, mTextureRectContainer ); + } + + return Texture(); +} + +bool AnimatedImageVisual::DisplayNextFrame() +{ + mCurrentFrameIndex = (mCurrentFrameIndex+1) % mFrameDelayContainer.Count(); + mImpl->mRenderer.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, mTextureRectContainer[mCurrentFrameIndex] ); + if( mFrameDelayTimer.GetInterval() != mFrameDelayContainer[mCurrentFrameIndex] ) + { + mFrameDelayTimer.SetInterval( mFrameDelayContainer[mCurrentFrameIndex] ); + } + + return true; +} + + +} // namespace Internal + +} // namespace Toolkit + +} // namespace Dali diff --git a/dali-toolkit/internal/visuals/animated-image/animated-image-visual.h b/dali-toolkit/internal/visuals/animated-image/animated-image-visual.h new file mode 100644 index 0000000..15dff43 --- /dev/null +++ b/dali-toolkit/internal/visuals/animated-image/animated-image-visual.h @@ -0,0 +1,156 @@ +#ifndef DALI_TOOLKIT_INTERNAL_ANIMATED_IMAGE_VISUAL_H +#define DALI_TOOLKIT_INTERNAL_ANIMATED_IMAGE_VISUAL_H + +/* + * Copyright (c) 2016 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 +#include +#include +#include + +// INTERNAL INCLUDES +#include + +namespace Dali +{ + +namespace Toolkit +{ + +namespace Internal +{ + +class AnimatedImageVisual; +typedef IntrusivePtr< AnimatedImageVisual > AnimatedImageVisualPtr; + +/** + * The visual which renders an animated image + * + * The following property is essential + * + * | %Property Name | Type | + * |--------------------------|------------------| + * | url | STRING | + * + */ + +class AnimatedImageVisual : public Visual::Base, public ConnectionTracker +{ + +public: + + /** + * @brief Create the animated image Visual using the image URL. + * + * @param[in] factoryCache A pointer pointing to the VisualFactoryCache object + * @param[in] imageUrl The URL to svg resource to use + * @param[in] properties A Property::Map containing settings for this visual + * @return A smart-pointer to the newly allocated visual. + */ + static AnimatedImageVisualPtr New( VisualFactoryCache& factoryCache, const std::string& imageUrl, const Property::Map& properties ); + + /** + * @brief Create the animated image visual using the image URL. + * + * @param[in] factoryCache A pointer pointing to the VisualFactoryCache object + * @param[in] imageUrl The URL to animated image resource to use + */ + static AnimatedImageVisualPtr New( VisualFactoryCache& factoryCache, const std::string& imageUrl ); + +public: // from Visual + + /** + * @copydoc Visual::Base::GetNaturalSize + */ + virtual void GetNaturalSize( Vector2& naturalSize ); + + /** + * @copydoc Visual::Base::CreatePropertyMap + */ + virtual void DoCreatePropertyMap( Property::Map& map ) const; + +protected: + + /** + * @brief Constructor. + * + * @param[in] factoryCache A pointer pointing to the VisualFactoryCache object + */ + AnimatedImageVisual( VisualFactoryCache& factoryCache ); + + /** + * @brief A reference counted object may only be deleted by calling Unreference(). + */ + virtual ~AnimatedImageVisual(); + + /** + * @copydoc Visual::Base::DoSetProperties + */ + virtual void DoSetProperties( const Property::Map& propertyMap ); + + /** + * @copydoc Visual::Base::DoSetOnStage + */ + virtual void DoSetOnStage( Actor& actor ); + + /** + * @copydoc Visual::Base::DoSetOffStage + */ + virtual void DoSetOffStage( Actor& actor ); + + /** + * @copydoc Visual::Base::OnSetTransform + */ + virtual void OnSetTransform(); + +private: + + /** + * Load the animated image and pack the frames into atlas. + * @return That atlas texture. + */ + Texture PrepareAnimatedImage(); + + /** + * Display the next frame. It is called when the mFrameDelayTimes ticks. + */ + bool DisplayNextFrame(); + + // Undefined + AnimatedImageVisual( const AnimatedImageVisual& animatedImageVisual ); + + // Undefined + AnimatedImageVisual& operator=( const AnimatedImageVisual& animatedImageVisual ); + +private: + + Timer mFrameDelayTimer; + Dali::Vector mTextureRectContainer; + Dali::Vector mFrameDelayContainer; + std::string mImageUrl; + ImageDimensions mImageSize; + uint32_t mCurrentFrameIndex; +}; + +} // namespace Internal + +} // namespace Toolkit + +} // namespace Dali +#endif /* DALI_TOOLKIT_INTERNAL_ANIMATED_IMAGE_VISUAL_H */ diff --git a/dali-toolkit/internal/visuals/color/color-visual.cpp b/dali-toolkit/internal/visuals/color/color-visual.cpp index 08dfd20..5bc3c6e 100644 --- a/dali-toolkit/internal/visuals/color/color-visual.cpp +++ b/dali-toolkit/internal/visuals/color/color-visual.cpp @@ -131,11 +131,6 @@ void ColorVisual::OnSetTransform() void ColorVisual::InitializeRenderer() { Geometry geometry = mFactoryCache.GetGeometry( VisualFactoryCache::QUAD_GEOMETRY ); - if( !geometry ) - { - geometry = VisualFactoryCache::CreateQuadGeometry(); - mFactoryCache.SaveGeometry( VisualFactoryCache::QUAD_GEOMETRY, geometry ); - } Shader shader = mFactoryCache.GetShader( VisualFactoryCache::COLOR_SHADER ); if( !shader ) diff --git a/dali-toolkit/internal/visuals/gradient/gradient-visual.cpp b/dali-toolkit/internal/visuals/gradient/gradient-visual.cpp index 80c899f..7826984 100644 --- a/dali-toolkit/internal/visuals/gradient/gradient-visual.cpp +++ b/dali-toolkit/internal/visuals/gradient/gradient-visual.cpp @@ -322,11 +322,6 @@ void GradientVisual::DoCreatePropertyMap( Property::Map& map ) const void GradientVisual::InitializeRenderer() { Geometry geometry = mFactoryCache.GetGeometry( VisualFactoryCache::QUAD_GEOMETRY ); - if( !geometry ) - { - geometry = VisualFactoryCache::CreateQuadGeometry(); - mFactoryCache.SaveGeometry( VisualFactoryCache::QUAD_GEOMETRY, geometry ); - } Toolkit::GradientVisual::Units::Type gradientUnits = mGradient->GetGradientUnits(); VisualFactoryCache::ShaderType shaderType = GetShaderType( mGradientType, gradientUnits ); diff --git a/dali-toolkit/internal/visuals/image/image-visual.cpp b/dali-toolkit/internal/visuals/image/image-visual.cpp index 69a1094..b61c23b 100644 --- a/dali-toolkit/internal/visuals/image/image-visual.cpp +++ b/dali-toolkit/internal/visuals/image/image-visual.cpp @@ -185,11 +185,6 @@ Geometry CreateGeometry( VisualFactoryCache& factoryCache, ImageDimensions gridS if( gridSize == ImageDimensions( 1, 1 ) ) { geometry = factoryCache.GetGeometry( VisualFactoryCache::QUAD_GEOMETRY ); - if( !geometry ) - { - geometry = VisualFactoryCache::CreateQuadGeometry(); - factoryCache.SaveGeometry( VisualFactoryCache::QUAD_GEOMETRY, geometry ); - } } else { diff --git a/dali-toolkit/internal/visuals/svg/svg-visual.cpp b/dali-toolkit/internal/visuals/svg/svg-visual.cpp index 5dbb80f..955b84c 100644 --- a/dali-toolkit/internal/visuals/svg/svg-visual.cpp +++ b/dali-toolkit/internal/visuals/svg/svg-visual.cpp @@ -100,11 +100,6 @@ void SvgVisual::DoSetOnStage( Actor& actor ) { Shader shader = ImageVisual::GetImageShader( mFactoryCache, true, true ); Geometry geometry = mFactoryCache.GetGeometry( VisualFactoryCache::QUAD_GEOMETRY ); - if( !geometry ) - { - geometry = mFactoryCache.CreateQuadGeometry(); - mFactoryCache.SaveGeometry( VisualFactoryCache::QUAD_GEOMETRY, geometry ); - } TextureSet textureSet = TextureSet::New(); mImpl->mRenderer = Renderer::New( geometry, shader ); mImpl->mRenderer.SetTextures( textureSet ); diff --git a/dali-toolkit/internal/visuals/text/text-visual.cpp b/dali-toolkit/internal/visuals/text/text-visual.cpp index 2e7fa6d..4145bf7 100644 --- a/dali-toolkit/internal/visuals/text/text-visual.cpp +++ b/dali-toolkit/internal/visuals/text/text-visual.cpp @@ -269,11 +269,6 @@ void TextVisual::DoSetOnStage( Actor& actor ) mControl = actor; Geometry geometry = mFactoryCache.GetGeometry( VisualFactoryCache::QUAD_GEOMETRY ); - if( !geometry ) - { - geometry = VisualFactoryCache::CreateQuadGeometry(); - mFactoryCache.SaveGeometry( VisualFactoryCache::QUAD_GEOMETRY , geometry ); - } Shader shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_ATLAS_CLAMP ); mFactoryCache.SaveShader( VisualFactoryCache::IMAGE_SHADER_ATLAS_DEFAULT_WRAP, shader ); diff --git a/dali-toolkit/internal/visuals/visual-factory-cache.cpp b/dali-toolkit/internal/visuals/visual-factory-cache.cpp index bf6814d..05e32ff 100644 --- a/dali-toolkit/internal/visuals/visual-factory-cache.cpp +++ b/dali-toolkit/internal/visuals/visual-factory-cache.cpp @@ -52,6 +52,11 @@ VisualFactoryCache::~VisualFactoryCache() Geometry VisualFactoryCache::GetGeometry( GeometryType type ) { + if( !mGeometry[type] && type == QUAD_GEOMETRY ) + { + mGeometry[type] = CreateQuadGeometry(); + } + return mGeometry[type]; } diff --git a/dali-toolkit/internal/visuals/visual-factory-impl.cpp b/dali-toolkit/internal/visuals/visual-factory-impl.cpp index 92cc53c..239f5c4 100644 --- a/dali-toolkit/internal/visuals/visual-factory-impl.cpp +++ b/dali-toolkit/internal/visuals/visual-factory-impl.cpp @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -151,6 +152,10 @@ Toolkit::Visual::Base VisualFactory::CreateVisual( const Property::Map& property { visualPtr = SvgVisual::New( *( mFactoryCache.Get() ), imageUrl, propertyMap ); } + else if( UrlType::GIF == type ) + { + visualPtr = AnimatedImageVisual::New( *( mFactoryCache.Get() ), imageUrl, propertyMap ); + } else // Regular image { bool batchingEnabled( false ); @@ -259,6 +264,10 @@ Toolkit::Visual::Base VisualFactory::CreateVisual( const std::string& url, Image { visualPtr = SvgVisual::New( *( mFactoryCache.Get() ), url ); } + else if( UrlType::GIF == type ) + { + visualPtr = AnimatedImageVisual::New( *( mFactoryCache.Get() ), url ); + } else // Regular image { visualPtr = ImageVisual::New( *( mFactoryCache.Get() ), url, size ); diff --git a/dali-toolkit/internal/visuals/visual-factory-resolve-url.h b/dali-toolkit/internal/visuals/visual-factory-resolve-url.h index 1d3ffe3..2c1c45b 100644 --- a/dali-toolkit/internal/visuals/visual-factory-resolve-url.h +++ b/dali-toolkit/internal/visuals/visual-factory-resolve-url.h @@ -37,7 +37,8 @@ namespace UrlType { REGULAR_IMAGE, N_PATCH, - SVG + SVG, + GIF }; } @@ -55,7 +56,9 @@ inline UrlType::Type ResolveUrlType( const std::string& url ) // parsing from the end for better chance of early outs enum { SUFFIX, HASH, HASH_DOT } state = SUFFIX; char SVG[ 4 ] = { 'g', 'v', 's', '.' }; + char GIF[ 4 ] = { 'f', 'i', 'g', '.' }; unsigned int svgScore = 0; + unsigned int gifScore = 0; int index = count; while( --index >= 0 ) { @@ -69,6 +72,14 @@ inline UrlType::Type ResolveUrlType( const std::string& url ) return UrlType::SVG; } } + if( ( offsetFromEnd < sizeof(GIF) )&&( tolower( currentChar ) == GIF[ offsetFromEnd ] ) ) + { + // early out if GIF + if( ++gifScore == sizeof(GIF) ) + { + return UrlType::GIF; + } + } switch( state ) { case SUFFIX: diff --git a/docs/content/images/visuals/animated-image-visual.gif b/docs/content/images/visuals/animated-image-visual.gif new file mode 100644 index 0000000..ddc3312 Binary files /dev/null and b/docs/content/images/visuals/animated-image-visual.gif differ diff --git a/docs/content/shared-javascript-and-cpp-documentation/visuals.md b/docs/content/shared-javascript-and-cpp-documentation/visuals.md index 457d8e1..eaaaed5 100644 --- a/docs/content/shared-javascript-and-cpp-documentation/visuals.md +++ b/docs/content/shared-javascript-and-cpp-documentation/visuals.md @@ -30,7 +30,7 @@ Visuals have a **transform** field in the property map to allow layouting within | Dali::Toolkit::Visual::Transform::Property::OFFSET | offset | VECTOR2 | No | The offset of the visual. | | Dali::Toolkit::Visual::Transform::Property::SIZE | size | VECTOR2 | No | The size of the visual. | | Dali::Toolkit::Visual::Transform::Property::OFFSET_SIZE_MODE | offsetSizeMode | VECTOR4 | No | Whether the size or offset components are Relative or Absolute [More info](@ref offset-size-mode)| -| Dali::Toolkit::Visual::Transform::Property::ORIGIN | origin | INTEGER or STRING | No | The origin of the visual within the control's area. [More info](@ref align-type)] | +| Dali::Toolkit::Visual::Transform::Property::ORIGIN | origin | INTEGER or STRING | No | The origin of the visual within the control's area. [More info](@ref align-type) | | Dali::Toolkit::Visual::Transform::Property::ANCHOR_POINT | anchorPoint | INTEGER or STRING | No | The anchor point of the visual. [More info](@ref align-type)| @@ -282,6 +282,7 @@ Depending on the extension of the image, a different visual is provided to rende + [Normal (Quad)](@ref image-visual) + [N-Patch](@ref n-patch-visual) + [SVG](@ref svg-visual) + + [Animated Image]( @ref animated-image-visual ) ___________________________ @@ -440,6 +441,45 @@ control.background = url : "path-to-image.svg" }; ~~~ + +___________________________________________________________________________________________________ + +## Animated Image Visual {#animated-image-visual} + +Renders an animated image into the visual's quad geometry. Currently, only the GIF format is supported. + +![ ](../assets/img/visuals/animated-image-visual.gif) +![ ](animated-image-visual.gif) + +#### Properties Supported + +**VisualType:** Dali::Toolkit::Visual::IMAGE, "IMAGE" + +| Property | String | Type | Required | Description | +|-------------------------------------------|--------|:-------:|:--------:|----------------------------------| +| Dali::Toolkit::ImageVisual::Property::URL | url | STRING | Yes | The URL of the animated image. | + +#### Usage + +~~~{.cpp} +// C++ +Dali::Toolkit::Control control = Dali::Toolkit::Control::New(); + +control.SetProperty( Control::Property::BACKGROUND, + Property::Map().Add( Visual::Property::TYPE, Dali::Toolkit::Visual::IMAGE ) + .Add( Dali::Toolkit::ImageVisual::Property::URL, "path-to-image.gif" ) ); +~~~ + +~~~{.js} +// JavaScript +var control = new dali.Control( "Control" ); + +control.background = +{ + visualType : "IMAGE", + url : "path-to-image.gif" +}; +~~~ ___________________________________________________________________________________________________ ## Border Visual {#border-visual}