From 0d076a4f2a8fe30919944ba37a626d32f1947316 Mon Sep 17 00:00:00 2001 From: Andrew Cox Date: Mon, 23 Feb 2015 14:14:51 +0000 Subject: [PATCH] Image scaling and filtering on load across all applicable demos --- examples/bubble-effect/bubble-effect-example.cpp | 23 +++++++++++++++++++++-- examples/cluster/cluster-example.cpp | 16 ++++++++++++---- examples/cube-transition-effect/cube-transition-effect-example.cpp | 24 ++++++++++++++++++++++-- examples/dissolve-effect/dissolve-effect-example.cpp | 25 ++++++++++++++++++++++--- examples/image-scaling-irregular-grid/image-scaling-irregular-grid-example.cpp | 4 ++++ examples/motion-blur/motion-blur-example.cpp | 46 ++++++++++++++++++++++++++++++++++------------ examples/refraction-effect/refraction-effect-example.cpp | 22 ++++++++++++++++++++-- examples/scroll-view/scroll-view-example.cpp | 5 +++-- shared/view.h | 10 +++++++--- 9 files changed, 145 insertions(+), 30 deletions(-) diff --git a/examples/bubble-effect/bubble-effect-example.cpp b/examples/bubble-effect/bubble-effect-example.cpp index f48959a..f86daa4 100644 --- a/examples/bubble-effect/bubble-effect-example.cpp +++ b/examples/bubble-effect/bubble-effect-example.cpp @@ -49,6 +49,25 @@ const unsigned int NUM_BUBBLE_SHAPE_IMAGES( sizeof( BUBBLE_SHAPE_IMAGES ) / size const Vector2 DEFAULT_BUBBLE_SIZE( 10.f, 30.f ); const unsigned int DEFAULT_NUMBER_OF_BUBBLES( 1000 ); + +/** + * @brief Load an image, scaled-down to no more than the stage dimensions. + * + * Uses image scaling mode ImageAttributes::ScaleToFill to resize the image at + * load time to cover the entire stage with pixels with no borders, + * and filter mode ImageAttributes::BoxThenLinear to sample the image with + * maximum quality. + */ +ResourceImage LoadStageFillingImage( const char * const imagePath ) +{ + Size stageSize = Stage::GetCurrent().GetSize(); + ImageAttributes attributes; + attributes.SetSize( stageSize.x, stageSize.y ); + attributes.SetFilterMode( ImageAttributes::BoxThenLinear ); + attributes.SetScalingMode( ImageAttributes::ScaleToFill ); + return ResourceImage::New( imagePath, attributes ); +} + }// end LOCAL_STUFF // This example shows the usage of BubbleEmitter which displays lots of moving bubbles on the stage. @@ -114,7 +133,7 @@ private: ResourceImage::New( BUBBLE_SHAPE_IMAGES[mCurrentBubbleShapeImageId] ), DEFAULT_NUMBER_OF_BUBBLES, DEFAULT_BUBBLE_SIZE); - mBackgroundImage = ResourceImage::New( BACKGROUND_IMAGES[mCurrentBackgroundImageId] ); + mBackgroundImage = LoadStageFillingImage( BACKGROUND_IMAGES[mCurrentBackgroundImageId] ); mBubbleEmitter.SetBackground( mBackgroundImage, mHSVDelta ); // Get the root actor of all bubbles, and add it to stage. @@ -235,7 +254,7 @@ private: { if(button == mChangeBackgroundButton) { - mBackgroundImage = ResourceImage::New( BACKGROUND_IMAGES[ ++mCurrentBackgroundImageId % NUM_BACKGROUND_IMAGES ] ); + mBackgroundImage = LoadStageFillingImage( BACKGROUND_IMAGES[ ++mCurrentBackgroundImageId % NUM_BACKGROUND_IMAGES ] ); mBubbleEmitter.SetBackground( mBackgroundImage, mHSVDelta ); diff --git a/examples/cluster/cluster-example.cpp b/examples/cluster/cluster-example.cpp index e8779cc..50b6d4d 100644 --- a/examples/cluster/cluster-example.cpp +++ b/examples/cluster/cluster-example.cpp @@ -524,7 +524,13 @@ public: const char **paths = IMAGE_GROUPS[clusterType]; DALI_ASSERT_ALWAYS(paths); - // Add a background image to the cluster + // Add a background image to the cluster, limiting the loaded size by + // fitting it inside a quarter of the stage area with the conservative Box + // filter mode: + Dali::ImageAttributes backgroundAttributes; + backgroundAttributes.SetSize( Stage::GetCurrent().GetSize() * 0.5f ); + backgroundAttributes.SetFilterMode( Dali::ImageAttributes::Box ); + backgroundAttributes.SetScalingMode( Dali::ImageAttributes::ShrinkToFit ); Image bg = ResourceImage::New( CLUSTER_BACKGROUND_IMAGE_PATH ); ImageActor image = ImageActor::New(bg); clusterActor.SetBackgroundImage(image); @@ -552,10 +558,12 @@ public: actor.SetParentOrigin( ParentOrigin::CENTER ); actor.SetAnchorPoint( AnchorPoint::CENTER ); - // Load the thumbnail + // Load the thumbnail at quarter of screen width or standard size if that is smaller: ImageAttributes attribs = ImageAttributes::New(); - attribs.SetSize(CLUSTER_IMAGE_THUMBNAIL_WIDTH, CLUSTER_IMAGE_THUMBNAIL_HEIGHT); - attribs.SetScalingMode(Dali::ImageAttributes::ShrinkToFit); + Size stageQuarter = Stage::GetCurrent().GetSize() * 0.25f; + attribs.SetSize( std::min( stageQuarter.x, CLUSTER_IMAGE_THUMBNAIL_WIDTH), std::min( stageQuarter.y, CLUSTER_IMAGE_THUMBNAIL_HEIGHT ) ); + attribs.SetFilterMode( Dali::ImageAttributes::BoxThenLinear ); + attribs.SetScalingMode(Dali::ImageAttributes::ShrinkToFit ); // Add a shadow image child actor Image shadowImage = ResourceImage::New( CLUSTER_SHADOW_IMAGE_PATH, attribs ); diff --git a/examples/cube-transition-effect/cube-transition-effect-example.cpp b/examples/cube-transition-effect/cube-transition-effect-example.cpp index 589caf3..7fa1545 100644 --- a/examples/cube-transition-effect/cube-transition-effect-example.cpp +++ b/examples/cube-transition-effect/cube-transition-effect-example.cpp @@ -85,6 +85,25 @@ const float CUBE_DISPLACEMENT_CROSS(30.f); // The duration of the current image staying on screen when slideshow is on const int VIEWINGTIME = 2000; // 2 seconds + +/** + * @brief Load an image, scaled-down to no more than the stage dimensions. + * + * Uses image scaling mode ImageAttributes::ScaleToFill to resize the image at + * load time to cover the entire stage with pixels with no borders, + * and filter mode ImageAttributes::BoxThenLinear to sample the image with + * maximum quality. + */ +ResourceImage LoadStageFillingImage( const char * const imagePath ) +{ + Size stageSize = Stage::GetCurrent().GetSize(); + ImageAttributes attributes; + attributes.SetSize( stageSize.x, stageSize.y ); + attributes.SetFilterMode( ImageAttributes::BoxThenLinear ); + attributes.SetScalingMode( ImageAttributes::ScaleToFill ); + return ResourceImage::New( imagePath, attributes ); +} + } // namespace class CubeTransitionApp : public ConnectionTracker @@ -266,7 +285,7 @@ void CubeTransitionApp::OnInit( Application& application ) // show the first image mImageConstraint = Constraint::New( Actor::Property::SCALE, LocalSource( Actor::Property::SIZE ), ParentSource( Actor::Property::SIZE ), ScaleToFitKeepAspectRatioConstraint() ); - mCurrentImage = ImageActor::New( ResourceImage::New( IMAGES[mIndex] ) ); + mCurrentImage = ImageActor::New( LoadStageFillingImage( IMAGES[mIndex] ) ); mCurrentImage.SetPositionInheritanceMode( USE_PARENT_POSITION ); mCurrentImage.ApplyConstraint( mImageConstraint ); mParent.Add( mCurrentImage ); @@ -308,8 +327,9 @@ void CubeTransitionApp::OnPanGesture( Actor actor, const PanGesture& gesture ) void CubeTransitionApp::GoToNextImage() { - ResourceImage image = ResourceImage::New( IMAGES[ mIndex ] ); + ResourceImage image = LoadStageFillingImage( IMAGES[ mIndex ] ); mNextImage = ImageActor::New( image ); + mNextImage.SetPositionInheritanceMode(USE_PARENT_POSITION); mNextImage.ApplyConstraint( mImageConstraint ); mCurrentEffect.SetTargetImage(mNextImage); diff --git a/examples/dissolve-effect/dissolve-effect-example.cpp b/examples/dissolve-effect/dissolve-effect-example.cpp index e2c7889..ac4e699 100644 --- a/examples/dissolve-effect/dissolve-effect-example.cpp +++ b/examples/dissolve-effect/dissolve-effect-example.cpp @@ -71,6 +71,25 @@ const int VIEWINGTIME = 2000; // 2 seconds const float TRANSITION_DURATION = 2.5f; //2.5 second const float INITIAL_DEPTH = -10.0f; + +/** + * @brief Load an image, scaled-down to no more than the stage dimensions. + * + * Uses image scaling mode ImageAttributes::ScaleToFill to resize the image at + * load time to cover the entire stage with pixels with no borders, + * and filter mode ImageAttributes::BoxThenLinear to sample the image with + * maximum quality. + */ +ResourceImage LoadStageFillingImage( const char * const imagePath ) +{ + Size stageSize = Stage::GetCurrent().GetSize(); + ImageAttributes attributes; + attributes.SetSize( stageSize.x, stageSize.y ); + attributes.SetFilterMode( ImageAttributes::BoxThenLinear ); + attributes.SetScalingMode( ImageAttributes::ScaleToFill ); + return ResourceImage::New( imagePath, attributes ); +} + } // namespace class DissolveEffectApp : public ConnectionTracker @@ -235,7 +254,7 @@ void DissolveEffectApp::OnInit( Application& application ) mSizeConstraint= Constraint::New( Actor::Property::SCALE, LocalSource( Actor::Property::SIZE ), ParentSource( Actor::Property::SIZE ), ScaleToFitKeepAspectRatioConstraint() ); // show the first image - mCurrentImage = ImageActor::New( ResourceImage::New( IMAGES[mIndex] ) ); + mCurrentImage = ImageActor::New( LoadStageFillingImage( IMAGES[mIndex] ) ); mCurrentImage.SetPositionInheritanceMode(USE_PARENT_POSITION_PLUS_LOCAL_POSITION); mCurrentImage.ApplyConstraint( mSizeConstraint ); mParent.Add( mCurrentImage ); @@ -263,7 +282,7 @@ void DissolveEffectApp::OnPanGesture( Actor actor, const PanGesture& gesture ) mIndex = (mIndex + NUM_IMAGES -1)%NUM_IMAGES; } - Image image = ResourceImage::New( IMAGES[ mIndex ] ); + Image image = LoadStageFillingImage( IMAGES[ mIndex ] ); mNextImage = ImageActor::New( image ); mNextImage.SetPositionInheritanceMode(USE_PARENT_POSITION_PLUS_LOCAL_POSITION); mNextImage.ApplyConstraint( mSizeConstraint ); @@ -375,7 +394,7 @@ bool DissolveEffectApp::OnTimerTick() if(mSlideshow) { mIndex = (mIndex + 1)%NUM_IMAGES; - Image image = ResourceImage::New( IMAGES[ mIndex ] ); + Image image = LoadStageFillingImage( IMAGES[ mIndex ] ); mNextImage = ImageActor::New( image ); mNextImage.SetPositionInheritanceMode(USE_PARENT_POSITION_PLUS_LOCAL_POSITION); mNextImage.ApplyConstraint( mSizeConstraint ); diff --git a/examples/image-scaling-irregular-grid/image-scaling-irregular-grid-example.cpp b/examples/image-scaling-irregular-grid/image-scaling-irregular-grid-example.cpp index 437194c..09bfe9e 100644 --- a/examples/image-scaling-irregular-grid/image-scaling-irregular-grid-example.cpp +++ b/examples/image-scaling-irregular-grid/image-scaling-irregular-grid-example.cpp @@ -183,6 +183,7 @@ Image CreateImage(const std::string& filename, unsigned int width, unsigned int attributes.SetSize( width, height ); attributes.SetScalingMode( scalingMode ); + attributes.SetFilterMode( ImageAttributes::BoxThenLinear ); Image image = ResourceImage::New( filename, attributes ); return image; } @@ -359,6 +360,9 @@ public: mContentLayer.Add( mScrollView ); mScrollView.Add( imageField ); mGridActor = imageField; + + // Scroll to top of grid so first images loaded are on-screen: + mScrollView.ScrollTo( Vector3( 0, -1000000, 0 ) ); } /** diff --git a/examples/motion-blur/motion-blur-example.cpp b/examples/motion-blur/motion-blur-example.cpp index e6bd57b..02032c7 100644 --- a/examples/motion-blur/motion-blur-example.cpp +++ b/examples/motion-blur/motion-blur-example.cpp @@ -88,9 +88,25 @@ const Vector3 BUTTON_TITLE_LABEL_INSTRUCTIONS_POPUP_SIZE_CONSTRAINT( 1.0f, 1.0f, const float BUTTON_TITLE_LABEL_Y_OFFSET = 0.05f; const float ORIENTATION_DURATION = 0.5f; ///< Time to rotate to new orientation. -} // unnamed namespace +/** + * @brief Load an image, scaled-down to no more than the dimensions passed in. + * + * Uses ImageAttributes::ShrinkToFit which ensures the resulting image is + * smaller than or equal to the specified dimensions while preserving its + * original aspect ratio. + */ +ResourceImage LoadImageFittedInBox( const char * const imagePath, uint32_t maxWidth, uint32_t maxHeight ) +{ + // Load the image nicely scaled-down to fit within the specified max width and height: + ImageAttributes attributes; + attributes.SetSize( maxWidth, maxHeight); + attributes.SetFilterMode( ImageAttributes::BoxThenLinear ); + attributes.SetScalingMode( ImageAttributes::ShrinkToFit ); + return ResourceImage::New( imagePath, attributes ); +} +} // unnamed namespace // @@ -187,10 +203,15 @@ public: // Motion blurred actor // - Image image = ResourceImage::New( MOTION_BLUR_ACTOR_IMAGE1 ); + // Scale down actor to fit on very low resolution screens with space to interact: + Size stageSize = Stage::GetCurrent().GetSize(); + mMotionBlurActorSize = Size( std::min( stageSize.x * 0.3f, MOTION_BLUR_ACTOR_WIDTH ), std::min( stageSize.y * 0.3f, MOTION_BLUR_ACTOR_HEIGHT ) ); + mMotionBlurActorSize = Size( std::min( mMotionBlurActorSize.x, mMotionBlurActorSize.y ), std::min( mMotionBlurActorSize.x, mMotionBlurActorSize.y ) ); + + Image image = LoadImageFittedInBox( MOTION_BLUR_ACTOR_IMAGE1, mMotionBlurActorSize.x, mMotionBlurActorSize.y ); mMotionBlurImageActor = ImageActor::New(image); mMotionBlurImageActor.SetParentOrigin( ParentOrigin::CENTER ); - mMotionBlurImageActor.SetSize(MOTION_BLUR_ACTOR_WIDTH, MOTION_BLUR_ACTOR_HEIGHT); + mMotionBlurImageActor.SetSize(mMotionBlurActorSize.x, mMotionBlurActorSize.y); mContentLayer.Add( mMotionBlurImageActor ); @@ -207,8 +228,8 @@ public: mMotionBlurImageActor2 = ImageActor::New(image); mMotionBlurImageActor2.SetParentOrigin( ParentOrigin::CENTER ); - mMotionBlurImageActor2.SetSize(MOTION_BLUR_ACTOR_WIDTH, MOTION_BLUR_ACTOR_HEIGHT); - mMotionBlurImageActor2.SetPosition(MOTION_BLUR_ACTOR_WIDTH * 1.1f, 0.0f); + mMotionBlurImageActor2.SetSize(mMotionBlurActorSize.x, mMotionBlurActorSize.y); + mMotionBlurImageActor2.SetPosition(mMotionBlurActorSize.x * 1.1f, 0.0f); mMotionBlurImageActor.Add( mMotionBlurImageActor2 ); // Create shader used for doing motion blur @@ -225,8 +246,8 @@ public: mMotionBlurImageActor3 = ImageActor::New(image); mMotionBlurImageActor3.SetParentOrigin( ParentOrigin::CENTER ); - mMotionBlurImageActor3.SetSize(MOTION_BLUR_ACTOR_WIDTH, MOTION_BLUR_ACTOR_HEIGHT); - mMotionBlurImageActor3.SetPosition(-MOTION_BLUR_ACTOR_WIDTH * 1.1f, 0.0f); + mMotionBlurImageActor3.SetSize(mMotionBlurActorSize.x, mMotionBlurActorSize.y); + mMotionBlurImageActor3.SetPosition(-mMotionBlurActorSize.x * 1.1f, 0.0f); mMotionBlurImageActor.Add( mMotionBlurImageActor3 ); // Create shader used for doing motion blur @@ -243,8 +264,8 @@ public: mMotionBlurImageActor4 = ImageActor::New(image); mMotionBlurImageActor4.SetParentOrigin( ParentOrigin::CENTER ); - mMotionBlurImageActor4.SetSize(MOTION_BLUR_ACTOR_WIDTH, MOTION_BLUR_ACTOR_HEIGHT); - mMotionBlurImageActor4.SetPosition(0.0f, MOTION_BLUR_ACTOR_HEIGHT * 1.1f); + mMotionBlurImageActor4.SetSize(mMotionBlurActorSize.x, mMotionBlurActorSize.y); + mMotionBlurImageActor4.SetPosition(0.0f, mMotionBlurActorSize.y * 1.1f); mMotionBlurImageActor.Add( mMotionBlurImageActor4 ); // Create shader used for doing motion blur @@ -261,8 +282,8 @@ public: mMotionBlurImageActor5 = ImageActor::New(image); mMotionBlurImageActor5.SetParentOrigin( ParentOrigin::CENTER ); - mMotionBlurImageActor5.SetSize(MOTION_BLUR_ACTOR_WIDTH, MOTION_BLUR_ACTOR_HEIGHT); - mMotionBlurImageActor5.SetPosition(0.0f, -MOTION_BLUR_ACTOR_HEIGHT * 1.1f); + mMotionBlurImageActor5.SetSize(mMotionBlurActorSize.x, mMotionBlurActorSize.y); + mMotionBlurImageActor5.SetPosition(0.0f, -mMotionBlurActorSize.y * 1.1f); mMotionBlurImageActor.Add( mMotionBlurImageActor5 ); // Create shader used for doing motion blur @@ -478,7 +499,7 @@ public: mCurrentImage = 0; } - Image blurImage = ResourceImage::New( MOTION_BLUR_ACTOR_IMAGES[mCurrentImage] ); + Image blurImage = LoadImageFittedInBox( MOTION_BLUR_ACTOR_IMAGES[mCurrentImage], mMotionBlurActorSize.x, mMotionBlurActorSize.y ); mMotionBlurImageActor.SetImage(blurImage); } @@ -498,6 +519,7 @@ private: // Motion blur MotionBlurEffect mMotionBlurEffect; ImageActor mMotionBlurImageActor; + Size mMotionBlurActorSize; #ifdef MULTIPLE_MOTION_BLURRED_ACTORS MotionBlurEffect mMotionBlurEffect2; diff --git a/examples/refraction-effect/refraction-effect-example.cpp b/examples/refraction-effect/refraction-effect-example.cpp index 05859bd..7a3a290 100644 --- a/examples/refraction-effect/refraction-effect-example.cpp +++ b/examples/refraction-effect/refraction-effect-example.cpp @@ -65,6 +65,24 @@ struct LightOffsetConstraint float mRadius; }; +/** + * @brief Load an image, scaled-down to no more than the stage dimensions. + * + * Uses image scaling mode ImageAttributes::ScaleToFill to resize the image at + * load time to cover the entire stage with pixels with no borders, + * and filter mode ImageAttributes::BoxThenLinear to sample the image with + * maximum quality. + */ +ResourceImage LoadStageFillingImage( const char * const imagePath ) +{ + Size stageSize = Stage::GetCurrent().GetSize(); + ImageAttributes attributes; + attributes.SetSize( stageSize.x, stageSize.y ); + attributes.SetFilterMode( ImageAttributes::BoxThenLinear ); + attributes.SetScalingMode( ImageAttributes::ScaleToFill ); + return ResourceImage::New( imagePath, attributes ); +} + } // namespace /************************************************************************************************ @@ -338,7 +356,7 @@ private: mNoEffect = NoEffect::New(); // used in the other situations, basic render shader // Create the mesh from the obj file and add to stage mMaterial = Material::New( "Material" ) ; - mMaterial.SetDiffuseTexture(ResourceImage::New(TEXTURE_IMAGES[mCurrentTextureId])); + mMaterial.SetDiffuseTexture( LoadStageFillingImage( TEXTURE_IMAGES[mCurrentTextureId] ) ); CreateSurface( MESH_FILES[mCurrentMeshId] ); // Connect the callback to the touch signal on the mesh actor @@ -371,7 +389,7 @@ private: bool OnChangeTexture( Toolkit::Button button ) { mCurrentTextureId = ( mCurrentTextureId + 1 ) % NUM_TEXTURE_IMAGES; - mMaterial.SetDiffuseTexture(ResourceImage::New(TEXTURE_IMAGES[mCurrentTextureId])); + mMaterial.SetDiffuseTexture( LoadStageFillingImage( TEXTURE_IMAGES[mCurrentTextureId] ) ); return true; } diff --git a/examples/scroll-view/scroll-view-example.cpp b/examples/scroll-view/scroll-view-example.cpp index 7993519..b69ea83 100644 --- a/examples/scroll-view/scroll-view-example.cpp +++ b/examples/scroll-view/scroll-view-example.cpp @@ -315,7 +315,7 @@ private: { for(int column = 0;column