Added examples to test blurring an image
authorDavid Steele <david.steele@samsung.com>
Thu, 25 Oct 2018 19:01:58 +0000 (20:01 +0100)
committerDavid Steele <david.steele@samsung.com>
Mon, 29 Oct 2018 21:00:21 +0000 (21:00 +0000)
hello-world.example tests GaussianBlurView
Button 1 deactivates, Button 2 Activates,
Button 3 destroys, Button 4 recreates.

image-view-blur.example tests RenderTasks directly.
It uses both a Gaussian blur and downsampling (to mimic GaussianBlurView)

First, it creates a scene, setting the image to load immediately, and adds it to the stage, but sets
it's visibility to false so it doesn't render.

It waits for the image to finish loading, then it creates a chain of render tasks as follows:
The scene is rendered onto FB 1,
FB 1 is rendered into a preview FB 2 in the top left.
FB 1 is rendered into FB 3 using the gaussian blur shader horizontally, FB 3 is half-size
FB 3 is rendered into a preview FB 4 in the bottom left
FB 3 is rendered into FB 4 using the gaussian blur shader vertically, FB 4 is same size as FB 3
FB 4 is upsampled into FB 1
FB 1 is rendered into the final image view in the center.

Pressing 1 removes the render tasks, previews and camera actors, and grows the final image.

Change-Id: I0167657e87ee13342c57a61d984d09c2cbff6b93
Signed-off-by: David Steele <david.steele@samsung.com>
build/scripts/encode-shader [changed mode: 0644->0755]
examples/hello-world/hello-world-example.cpp
examples/image-view-blur/gaussian-blur-frag-shader.h [new file with mode: 0644]
examples/image-view-blur/image-view-blur.cpp
examples/image-view-blur/utils.cpp [new file with mode: 0644]
examples/image-view-blur/utils.h [new file with mode: 0644]

old mode 100644 (file)
new mode 100755 (executable)
index 779748e..bd124ef
@@ -23,9 +23,11 @@ my $opt_output;
 my $opt_help;
 my $opt_quiet;
 my $opt_verbose;
+my $opt_variable;
 
 my %options = (
     "output:s"     => { "optvar"=>\$opt_output, "desc"=>"output"},
+    "variable=s"   => { "optvar"=>\$opt_variable, "desc"=>"variable"},
     "help"         => { "optvar"=>\$opt_help, "desc"=>""},
     "quiet"        => { "optvar"=>\$opt_quiet, "desc"=>""},
     "verbose"      => { "optvar"=>\$opt_verbose, "desc"=>"" });
@@ -34,14 +36,17 @@ my %longOptions = map { $_ => $options{$_}->{"optvar"} } keys(%options);
 GetOptions( %longOptions ) or pod2usage(2);
 pod2usage(1) if $opt_help;
 
-if( $opt_output )
+my $var;
+if($opt_variable)
 {
+    $var = "--vn $opt_variable";
 }
 
 my $tempFile="/tmp/shader.spv$$";
 
 # Create a binary file from the main argument
-print `glslangValidator -V1.0 $ARGV[0] -vn -o $tempFile`;
+print " Executing: glslangValidator -V1.0 $ARGV[0] $var -o $tempFile\n";
+print `glslangValidator -V1.0 $ARGV[0] $var -o $tempFile`;
 open PIPE, "uuencode -m $tempFile $tempFile | " || die "Can't execute pipe: $!\n";
 
 my @lines;
index ad70d0d1e20ace5d6b417ab744b06482253017f4..4e3306b1d152b912e712d845e81d0146c7eb2195 100644 (file)
 #include <dali-toolkit/dali-toolkit.h>
 
 using namespace Dali;
-using Dali::Toolkit::TextLabel;
+using namespace Dali::Toolkit;
+#include <dali-toolkit/devel-api/controls/gaussian-blur-view/gaussian-blur-view.h>
 
-// This example shows how to create and display Hello World! using a simple TextActor
-//
-class HelloWorldController : public ConnectionTracker
+const char* URL="https://upload.wikimedia.org/wikipedia/commons/2/2c/NZ_Landscape_from_the_van.jpg";
+
+/**
+ * This example shows how to use GaussianBlur UI control.
+ */
+class ImageBlurExample : public ConnectionTracker
 {
 public:
 
-  HelloWorldController( Application& application )
+  // Initialize variables and connect signal
+  ImageBlurExample( Application& application )
   : mApplication( application )
   {
     // Connect to the Application's Init signal
-    mApplication.InitSignal().Connect( this, &HelloWorldController::Create );
+    mApplication.InitSignal().Connect( this, &ImageBlurExample::Create );
   }
 
-  ~HelloWorldController()
+  ~ImageBlurExample()
   {
     // Nothing to do here;
   }
@@ -42,47 +47,102 @@ public:
   void Create( Application& application )
   {
     // Get a handle to the stage
-    Stage stage = Stage::GetCurrent();
-    stage.SetBackgroundColor( Color::WHITE );
+    mStage = Stage::GetCurrent();
+    // Set stage background color
+    mStage.SetBackgroundColor( Color::BLACK );
+    mStage.KeyEventSignal().Connect(this, &ImageBlurExample::OnKeyEvent);
 
-    TextLabel textLabel = TextLabel::New( "Hello World" );
-    textLabel.SetAnchorPoint( AnchorPoint::TOP_LEFT );
-    textLabel.SetName( "helloWorldLabel" );
-    stage.Add( textLabel );
+    mImageView = ImageView::New();
+    mImageView.SetProperty(ImageView::Property::IMAGE, Property::Map()
+                           .Add(ImageVisual::Property::URL, URL)
+                           .Add(ImageVisual::Property::LOAD_POLICY, ImageVisual::LoadPolicy::IMMEDIATE ) );
 
-    // Respond to a click anywhere on the stage
-    stage.GetRootLayer().TouchSignal().Connect( this, &HelloWorldController::OnTouch );
+    mImageView.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
+    mImageView.SetAnchorPoint(AnchorPoint::TOP_LEFT);
 
-    // Respond to key events
-    stage.KeyEventSignal().Connect( this, &HelloWorldController::OnKeyEvent );
+    auto sceneText = TextLabel::New( "Landscape photo");
+    sceneText.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS );
+    sceneText.SetProperty( TextLabel::Property::POINT_SIZE, 40 );
+    sceneText.SetProperty( TextLabel::Property::TEXT_COLOR, Color::BLACK );
+    sceneText.SetProperty( TextLabel::Property::OUTLINE, Property::Map().Add("color",Color::WHITE).Add("width", 2) );
+    sceneText.SetParentOrigin( ParentOrigin::BOTTOM_CENTER );
+    sceneText.SetAnchorPoint( AnchorPoint::BOTTOM_CENTER );
+    sceneText.SetName("SceneText");
+    mImageView.Add(sceneText);
+
+    CreateBlurView( mImageView );
+    mStage.KeepRendering( 1000000.0f );
   }
 
-  bool OnTouch( Actor actor, const TouchData& touch )
+  void CreateBlurView( Actor scene )
   {
-    // quit the application
-    mApplication.Quit();
-    return true;
+    mGaussianBlurView = GaussianBlurView::New(5, 1.5f, 0.5f, 0.5f);
+    mGaussianBlurView.SetSize(mStage.GetSize()*0.8f);
+    mGaussianBlurView.SetAnchorPoint( AnchorPoint::CENTER );
+    mGaussianBlurView.SetParentOrigin( ParentOrigin::CENTER );
+    mGaussianBlurView.SetVisible( true );
+    mGaussianBlurView.Add( scene );
+    mGaussianBlurView.SetBackgroundColor( Color::MAGENTA ); // All render tasks should use this color...
+
+    mStage.Add(mGaussianBlurView);
+    mGaussianBlurView.Activate();
   }
 
-  void OnKeyEvent( const KeyEvent& event )
+
+  void OnKeyEvent(const KeyEvent& event)
   {
-    if( event.state == KeyEvent::Down )
+    if(event.state == KeyEvent::Down)
     {
-      if ( IsKey( event, Dali::DALI_KEY_ESCAPE ) || IsKey( event, Dali::DALI_KEY_BACK ) )
+      if( IsKey( event, DALI_KEY_ESCAPE) || IsKey( event, DALI_KEY_BACK ) )
       {
         mApplication.Quit();
       }
+      if( event.keyCode == 10 )
+      {
+        if( mGaussianBlurView )
+        {
+          mGaussianBlurView.Deactivate();
+          printf("Deactivated\n");
+        }
+      }
+      else if( event.keyCode == 11 )
+      {
+        if( mGaussianBlurView )
+        {
+          mGaussianBlurView.Activate();
+          printf("Activated\n");
+        }
+      }
+      else if( event.keyCode == 12 )
+      {
+        UnparentAndReset( mGaussianBlurView );
+        printf("Destroyed\n");
+      }
+      else if( event.keyCode == 13 )
+      {
+        CreateBlurView( mImageView );
+        printf("Re-created\n");
+      }
     }
   }
 
 private:
   Application&  mApplication;
+  Stage mStage;
+  GaussianBlurView mGaussianBlurView;
+  ImageView mImageView;
+
 };
 
-int DALI_EXPORT_API main( int argc, char **argv )
+// Entry point for Linux & Tizen applications
+int main(int argc, char **argv)
 {
-  Application application = Application::New( &argc, &argv );
-  HelloWorldController test( application );
-  application.MainLoop();
+  // Create application instance
+  Application app = Application::New(&argc, &argv);
+  ImageBlurExample test(app);
+
+  // Start application.
+  app.MainLoop();
+
   return 0;
 }
diff --git a/examples/image-view-blur/gaussian-blur-frag-shader.h b/examples/image-view-blur/gaussian-blur-frag-shader.h
new file mode 100644 (file)
index 0000000..72ac845
--- /dev/null
@@ -0,0 +1,63 @@
+std::vector<uint32_t> GAUSSIAN_BLUR_FRAG_SHADER = {
+  0x07230203,0x00010000,0x00080001,0x00000044,0x00000000,0x00020011,0x00000001,0x0006000b,
+  0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001,
+  0x0007000f,0x00000004,0x00000004,0x6e69616d,0x00000000,0x00000011,0x00000042,0x00030010,
+  0x00000004,0x00000007,0x00030003,0x00000002,0x000001ae,0x00040005,0x00000004,0x6e69616d,
+  0x00000000,0x00030005,0x00000009,0x006c6f63,0x00050005,0x0000000d,0x78655473,0x65727574,
+  0x00000000,0x00050005,0x00000011,0x78655476,0x726f6f43,0x00000064,0x00050005,0x00000017,
+  0x67617246,0x61746144,0x00000000,0x00050006,0x00000017,0x00000000,0x6c6f4375,0x0000726f,
+  0x00070006,0x00000017,0x00000001,0x6d615375,0x4f656c70,0x65736666,0x00007374,0x00070006,
+  0x00000017,0x00000002,0x6d615375,0x57656c70,0x68676965,0x00007374,0x00030005,0x00000019,
+  0x00000000,0x00030005,0x00000028,0x00000069,0x00050005,0x00000042,0x67617266,0x6f6c6f43,
+  0x00000072,0x00030047,0x00000009,0x00000000,0x00040047,0x0000000d,0x00000022,0x00000000,
+  0x00040047,0x0000000d,0x00000021,0x00000002,0x00030047,0x00000011,0x00000000,0x00040047,
+  0x00000011,0x0000001e,0x00000000,0x00030047,0x00000012,0x00000000,0x00040047,0x00000015,
+  0x00000006,0x00000010,0x00040047,0x00000016,0x00000006,0x00000010,0x00040048,0x00000017,
+  0x00000000,0x00000000,0x00050048,0x00000017,0x00000000,0x00000023,0x00000000,0x00040048,
+  0x00000017,0x00000001,0x00000000,0x00050048,0x00000017,0x00000001,0x00000023,0x00000010,
+  0x00040048,0x00000017,0x00000002,0x00000000,0x00050048,0x00000017,0x00000002,0x00000023,
+  0x00000060,0x00030047,0x00000017,0x00000002,0x00040047,0x00000019,0x00000022,0x00000000,
+  0x00040047,0x00000019,0x00000021,0x00000001,0x00030047,0x0000001f,0x00000000,0x00030047,
+  0x00000020,0x00000000,0x00030047,0x00000025,0x00000000,0x00030047,0x00000033,0x00000000,
+  0x00030047,0x00000036,0x00000000,0x00030047,0x00000037,0x00000000,0x00030047,0x0000003b,
+  0x00000000,0x00030047,0x0000003d,0x00000000,0x00040047,0x00000042,0x0000001e,0x00000000,
+  0x00030047,0x00000043,0x00000000,0x00020013,0x00000002,0x00030021,0x00000003,0x00000002,
+  0x00030016,0x00000006,0x00000020,0x00040017,0x00000007,0x00000006,0x00000004,0x00040020,
+  0x00000008,0x00000007,0x00000007,0x00090019,0x0000000a,0x00000006,0x00000001,0x00000000,
+  0x00000000,0x00000000,0x00000001,0x00000000,0x0003001b,0x0000000b,0x0000000a,0x00040020,
+  0x0000000c,0x00000000,0x0000000b,0x0004003b,0x0000000c,0x0000000d,0x00000000,0x00040017,
+  0x0000000f,0x00000006,0x00000002,0x00040020,0x00000010,0x00000001,0x0000000f,0x0004003b,
+  0x00000010,0x00000011,0x00000001,0x00040015,0x00000013,0x00000020,0x00000000,0x0004002b,
+  0x00000013,0x00000014,0x00000005,0x0004001c,0x00000015,0x0000000f,0x00000014,0x0004001c,
+  0x00000016,0x00000006,0x00000014,0x0005001e,0x00000017,0x00000007,0x00000015,0x00000016,
+  0x00040020,0x00000018,0x00000002,0x00000017,0x0004003b,0x00000018,0x00000019,0x00000002,
+  0x00040015,0x0000001a,0x00000020,0x00000001,0x0004002b,0x0000001a,0x0000001b,0x00000001,
+  0x0004002b,0x0000001a,0x0000001c,0x00000000,0x00040020,0x0000001d,0x00000002,0x0000000f,
+  0x0004002b,0x0000001a,0x00000022,0x00000002,0x00040020,0x00000023,0x00000002,0x00000006,
+  0x00040020,0x00000027,0x00000007,0x0000001a,0x0004002b,0x0000001a,0x0000002f,0x00000005,
+  0x00020014,0x00000030,0x00040020,0x00000041,0x00000003,0x00000007,0x0004003b,0x00000041,
+  0x00000042,0x00000003,0x00050036,0x00000002,0x00000004,0x00000000,0x00000003,0x000200f8,
+  0x00000005,0x0004003b,0x00000008,0x00000009,0x00000007,0x0004003b,0x00000027,0x00000028,
+  0x00000007,0x0004003d,0x0000000b,0x0000000e,0x0000000d,0x0004003d,0x0000000f,0x00000012,
+  0x00000011,0x00060041,0x0000001d,0x0000001e,0x00000019,0x0000001b,0x0000001c,0x0004003d,
+  0x0000000f,0x0000001f,0x0000001e,0x00050081,0x0000000f,0x00000020,0x00000012,0x0000001f,
+  0x00050057,0x00000007,0x00000021,0x0000000e,0x00000020,0x00060041,0x00000023,0x00000024,
+  0x00000019,0x00000022,0x0000001c,0x0004003d,0x00000006,0x00000025,0x00000024,0x0005008e,
+  0x00000007,0x00000026,0x00000021,0x00000025,0x0003003e,0x00000009,0x00000026,0x0003003e,
+  0x00000028,0x0000001b,0x000200f9,0x00000029,0x000200f8,0x00000029,0x000400f6,0x0000002b,
+  0x0000002c,0x00000000,0x000200f9,0x0000002d,0x000200f8,0x0000002d,0x0004003d,0x0000001a,
+  0x0000002e,0x00000028,0x000500b1,0x00000030,0x00000031,0x0000002e,0x0000002f,0x000400fa,
+  0x00000031,0x0000002a,0x0000002b,0x000200f8,0x0000002a,0x0004003d,0x0000000b,0x00000032,
+  0x0000000d,0x0004003d,0x0000000f,0x00000033,0x00000011,0x0004003d,0x0000001a,0x00000034,
+  0x00000028,0x00060041,0x0000001d,0x00000035,0x00000019,0x0000001b,0x00000034,0x0004003d,
+  0x0000000f,0x00000036,0x00000035,0x00050081,0x0000000f,0x00000037,0x00000033,0x00000036,
+  0x00050057,0x00000007,0x00000038,0x00000032,0x00000037,0x0004003d,0x0000001a,0x00000039,
+  0x00000028,0x00060041,0x00000023,0x0000003a,0x00000019,0x00000022,0x00000039,0x0004003d,
+  0x00000006,0x0000003b,0x0000003a,0x0005008e,0x00000007,0x0000003c,0x00000038,0x0000003b,
+  0x0004003d,0x00000007,0x0000003d,0x00000009,0x00050081,0x00000007,0x0000003e,0x0000003d,
+  0x0000003c,0x0003003e,0x00000009,0x0000003e,0x000200f9,0x0000002c,0x000200f8,0x0000002c,
+  0x0004003d,0x0000001a,0x0000003f,0x00000028,0x00050080,0x0000001a,0x00000040,0x0000003f,
+  0x0000001b,0x0003003e,0x00000028,0x00000040,0x000200f9,0x00000029,0x000200f8,0x0000002b,
+  0x0004003d,0x00000007,0x00000043,0x00000009,0x0003003e,0x00000042,0x00000043,0x000100fd,
+  0x00010038
+};
index 48f4f2c8db63975d06503f24ce7ce95836d71698..f4232492747013089ab1db3bd45b7bb77a524279 100644 (file)
  */
 
 #include <dali-toolkit/dali-toolkit.h>
-#include <dali-toolkit/devel-api/controls/gaussian-blur-view/gaussian-blur-view.h>
+#include <dali-toolkit/devel-api/builder/base64-encoding.h>
+#include <dali-toolkit/devel-api/image-loader/texture-manager.h>
+#include "gaussian-blur-frag-shader.h"
+#include "utils.h"
 
 using namespace Dali;
 using namespace Dali::Toolkit;
 
+namespace
+{
+const Vector2 TARGET_SIZE(960.f, 480.f);
+const char* URL="https://upload.wikimedia.org/wikipedia/commons/2/2c/NZ_Landscape_from_the_van.jpg";
+}
+
 class ImageViewBlurExample : public ConnectionTracker
 {
 public:
@@ -33,44 +42,124 @@ public:
   {
     auto stage = Stage::GetCurrent();
     stage.KeyEventSignal().Connect(this, &ImageViewBlurExample::OnKeyEvent);
+    stage.SetBackgroundColor( Vector4( 0.2f, 0.1f, 0.2f, 1.0f ) );
+
+    mSceneActor = CreateScene( TARGET_SIZE );
 
-    CreateBlurView1();
+    // Don't add to stage until it's ready.... Must use immediate only.
+    // If image view's aren't added with loading policy = Immediate, then the render task cannot use REFRESH_ONCE,
+    // and must run until de-activated
+
+    // Build render tasks in ready callback.
+    Stage::GetCurrent().Add( mSceneActor ); // Will make all text labels ready
+    mSceneActor.SetVisible(false);
   }
 
-  void CreateBlurView1()
+
+  Actor CreateScene( Vector2 targetSize )
   {
-    auto stage = Stage::GetCurrent();
-    auto size = stage.GetSize();
-    auto image1 = ImageView::New( DEMO_IMAGE_DIR "background-1.jpg" );
-    image1.SetSize( size * 0.5f );
-
-    blurView1 = GaussianBlurView::New();
-    blurView1.SetSize( size * 0.5f );
-    blurView1.SetParentOrigin( ParentOrigin::CENTER );//  Vector3(0.0f, -0.25f, 0.0f) );
-    blurView1.SetAnchorPoint( AnchorPoint::CENTER );
-    blurView1.Add( image1 );
-    //blurView1.SetBackgroundColor( Color::RED );
-
-    image1.SetParentOrigin( ParentOrigin::CENTER );
-    image1.SetAnchorPoint( AnchorPoint::CENTER );
-    blurView1.Activate();
-
-    blurView1.SetProperty(blurView1.GetBlurStrengthPropertyIndex(), 1.0f);
-    auto blurAnim = Animation::New(0.5f);
-    blurAnim.AnimateTo( Property( blurView1, blurView1.GetBlurStrengthPropertyIndex() ), 1.0f);
-    blurAnim.FinishedSignal().Connect( this, &ImageViewBlurExample::OnBlurAnimFinished );
-    blurAnim.Play();
-    stage.Add(blurView1);
+    auto sceneActor = Actor::New();
+    sceneActor.SetResizePolicy( ResizePolicy::FIT_TO_CHILDREN, Dimension::ALL_DIMENSIONS );
+    sceneActor.SetParentOrigin( ParentOrigin::CENTER );
+    auto sceneImage = ImageView::New();
+    sceneImage.SetProperty(ImageView::Property::IMAGE, Property::Map()
+                           .Add( ImageVisual::Property::URL, URL )
+                           .Add( ImageVisual::Property::LOAD_POLICY, ImageVisual::LoadPolicy::IMMEDIATE ) );
+
+    sceneImage.ResourceReadySignal().Connect( this, &ImageViewBlurExample::OnImageReady );
+
+    sceneImage.SetSize( targetSize );
+    sceneImage.SetParentOrigin( ParentOrigin::CENTER );
+    sceneImage.SetAnchorPoint( AnchorPoint::CENTER );
+    sceneImage.SetName("SceneImage");
+    sceneActor.Add(sceneImage);
+
+    auto sceneText = TextLabel::New( "Landscape photo");
+    sceneText.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS );
+    sceneText.SetProperty( TextLabel::Property::POINT_SIZE, 40 );
+    sceneText.SetProperty( TextLabel::Property::TEXT_COLOR, Color::BLACK );
+    sceneText.SetProperty( TextLabel::Property::OUTLINE, Property::Map().Add("color",Color::WHITE).Add("width", 2) );
+    sceneText.SetParentOrigin( ParentOrigin::BOTTOM_CENTER );
+    sceneText.SetAnchorPoint( AnchorPoint::BOTTOM_CENTER );
+    sceneText.SetName("SceneText");
+    sceneImage.Add(sceneText);
+    return sceneActor;
   }
 
-  void OnBlurAnimFinished(Animation& anim)
+  void OnImageReady( Control control )
   {
-    blurView1.Deactivate();
+    mSceneActor.SetVisible(true);
+    CreateBlurView( mSceneActor, TARGET_SIZE ); // Renders the scene in an exclusive render task
+  }
+
+  /**
+   * Create a scene render + 2 stage filter, reusing Framebuffers
+   */
+  void CreateBlurView( Actor sceneActor, Vector2 targetSize )
+  {
+    auto stage = Stage::GetCurrent();
+
+    // Step 1 captures the scene into a framebuffer without any effects
+    auto step1Output = Texture::New( TextureType::TEXTURE_2D,
+                                     Pixel::RGBA8888,
+                                     unsigned(targetSize.width),
+                                     unsigned(targetSize.height) );
+
+    // Should be final size
+    auto fb1 = FrameBuffer::New(targetSize.width, targetSize.height, Pixel::RGBA8888);
+    fb1.AttachColorTexture( step1Output );
+
+    Utils::CreateRenderTask( sceneActor, targetSize, fb1 ); // Renders scene exclusively - it shouldn't be drawn to main fb
+    auto step1Url = TextureManager::AddTexture( step1Output );
+
+    mPreview1 = Utils::CreatePreview( step1Url, targetSize, ParentOrigin::TOP_LEFT, ParentOrigin::BOTTOM_LEFT,"Step 1", true );
+    stage.Add( mPreview1 );
+
+    // Step2 executes the first pass of the effect shader
+    // Can be reduced size:
+    Vector2 downscaledSize = targetSize * 0.5f;
+
+    auto step2Url = Utils::CreateEffectPassTexture( step1Url, GAUSSIAN_BLUR_FRAG_SHADER, downscaledSize,
+                                                    Utils::Direction::HORIZONTAL );
+
+    mPreview2 = Utils::CreatePreview( step2Url, targetSize, ParentOrigin::BOTTOM_LEFT, ParentOrigin::TOP_LEFT,
+                                      "Step 2", true );
+    stage.Add( mPreview2 );
+
+    // Step 3 renders the second pass of the effect shader
+    auto step3Url = Utils::CreateEffectPassTexture( step2Url, GAUSSIAN_BLUR_FRAG_SHADER, downscaledSize,
+                                                    Utils::Direction::VERTICAL );
+
+    // Don't bother with preview 3, we're going to draw it at larger scale back to original fbo
+    std::vector<uint32_t> empty;
+    Utils::CreateEffectPassTexture( step3Url, empty, targetSize, Utils::Direction::HORIZONTAL, fb1 );
+
+    // Render step 4 output (same as step 1 output) to center:
+    mFinalImage = ImageView::New( step1Url );
+    mFinalImage.SetSize( targetSize );
+    mFinalImage.SetParentOrigin( ParentOrigin::CENTER );
+    mFinalImage.SetAnchorPoint( AnchorPoint::CENTER );
+    stage.Add( mFinalImage );
   }
 
-  void OnBlurFinished(GaussianBlurView source)
+  void Deactivate()
   {
-    printf("Blur finished\n");
+    Stage stage = Stage::GetCurrent();
+    auto taskList = stage.GetRenderTaskList();
+    for( unsigned int i=taskList.GetTaskCount()-1; i>0; --i )
+    {
+      auto task = taskList.GetTask(i);
+      Actor cameraActor = task.GetCameraActor();
+      Actor sourceActor = task.GetSourceActor();
+      stage.Remove( cameraActor );
+      stage.Remove( sourceActor );
+      task.SetCameraActor( CameraActor() );
+      task.SetSourceActor( Actor() );
+      taskList.RemoveTask(taskList.GetTask(i));
+    }
+    UnparentAndReset(mPreview1);
+    UnparentAndReset(mPreview2);
+    mFinalImage.SetSize( TARGET_SIZE * 1.8f );
   }
 
   void OnKeyEvent(const KeyEvent& event)
@@ -81,13 +170,19 @@ public:
       {
         mApp.Quit();
       }
+      if( event.keyCode == 10 )
+      {
+        Deactivate();
+      }
     }
   }
 
 private:
   Application& mApp;
-  GaussianBlurView blurView1;
-  GaussianBlurView blurView2;
+  Actor mSceneActor;
+  ImageView mFinalImage;
+  Actor mPreview1;
+  Actor mPreview2;
 };
 
 int main( int argc, char** argv )
diff --git a/examples/image-view-blur/utils.cpp b/examples/image-view-blur/utils.cpp
new file mode 100644 (file)
index 0000000..ad80047
--- /dev/null
@@ -0,0 +1,240 @@
+#include "utils.h"
+
+#include <dali-toolkit/dali-toolkit.h>
+#include <dali-toolkit/devel-api/image-loader/texture-manager.h>
+#include <dali-toolkit/devel-api/builder/base64-encoding.h>
+#include <iostream>
+
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+
+namespace Utils
+{
+
+std::string CreateEffectPassTexture( std::string inputUrl, std::vector<uint32_t>& fragShader, Vector2 targetSize, Direction direction )
+{
+  auto outputTexture = Texture::New( TextureType::TEXTURE_2D,
+                                     Pixel::RGBA8888,
+                                     unsigned(targetSize.width),
+                                     unsigned(targetSize.height) );
+
+  auto framebuffer = FrameBuffer::New(targetSize.width, targetSize.height, Pixel::RGB888);
+  framebuffer.AttachColorTexture( outputTexture );
+
+  Actor image = CreateEffectPassTexture( inputUrl, fragShader, targetSize, direction, framebuffer );
+
+  auto url = Dali::Toolkit::TextureManager::AddTexture( outputTexture );
+  return url;
+}
+
+
+Actor CreateEffectPassTexture( std::string inputUrl, std::vector<uint32_t>& fragShader, Vector2 targetSize, Direction direction, FrameBuffer fb )
+{
+  auto image = ImageView::New( inputUrl );
+
+  if( fragShader.size() > 0 )
+  {
+    Property::Map visualMap;
+    Property::Map customShader;
+    Property::Value value;
+    Toolkit::EncodeBase64PropertyData( value, fragShader );
+    customShader[Toolkit::Visual::Shader::Property::FRAGMENT_SHADER] = value;
+    visualMap[Toolkit::Visual::Property::SHADER] = customShader;
+    image.SetProperty(Toolkit::ImageView::Property::IMAGE, visualMap);
+    SetShaderConstants( image, direction, 5, targetSize.x, targetSize.y );
+  }
+
+  image.SetParentOrigin( ParentOrigin::CENTER );
+  image.SetSize( targetSize );
+
+  Stage::GetCurrent().Add(image);
+
+  Utils::CreateRenderTask( image, targetSize, fb );
+  return image;
+}
+
+Actor CreatePreview( const std::string& url,
+                     Vector2 targetSize,
+                     Vector3 parentOrigin, Vector3 labelOrigin,
+                     const std::string& label, bool copy )
+{
+  Actor previewActor;
+  if( copy )
+  {
+    previewActor = CreatePreviewRenderTask( url, targetSize );
+  }
+  else
+  {
+    previewActor = ImageView::New( url );
+  }
+
+  previewActor.SetParentOrigin( parentOrigin );
+  previewActor.SetAnchorPoint( parentOrigin );
+  previewActor.SetSize( targetSize * 0.8f );
+
+  auto labelActor = TextLabel::New(label);
+  labelActor.SetResizePolicy(ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS);
+  labelActor.SetParentOrigin( labelOrigin );
+  labelActor.SetAnchorPoint( parentOrigin );
+  labelActor.SetProperty(TextLabel::Property::TEXT_COLOR, Color::WHITE);
+  previewActor.Add( labelActor );
+
+  return previewActor;
+}
+
+/**
+ * @param[in] url The url of the texture to copy
+ * @return An image view containing a copy of the texture
+ */
+Actor CreatePreviewRenderTask( std::string url, Vector2 targetSize )
+{
+  // Image for re-rendering to a second FB
+  auto image = ImageView::New( url );
+  image.SetSize( targetSize );
+  image.SetParentOrigin( ParentOrigin::CENTER );
+  image.SetAnchorPoint( AnchorPoint::CENTER );
+  Stage::GetCurrent().Add( image );
+
+  Texture previewOutput = Utils::CreateRenderTask( image, targetSize ); // Exclusive
+  auto previewUrl = Dali::Toolkit::TextureManager::AddTexture( previewOutput );
+
+  auto previewImage = ImageView::New( previewUrl );
+  previewImage.SetSize( targetSize * 0.4f );
+  return previewImage;
+}
+
+Texture CreateRenderTask(Actor inputActor, Vector2 targetSize)
+{
+  auto outputTexture = Texture::New( TextureType::TEXTURE_2D,
+                                     Pixel::RGBA8888,
+                                     unsigned(targetSize.width),
+                                     unsigned(targetSize.height) );
+
+  auto framebuffer = FrameBuffer::New(targetSize.width, targetSize.height, Pixel::RGBA8888);
+  framebuffer.AttachColorTexture( outputTexture );
+
+  Utils::CreateRenderTask( inputActor, targetSize, framebuffer );
+
+  return outputTexture;
+}
+
+void CreateRenderTask(Actor inputActor, Vector2 targetSize, FrameBuffer fbo )
+{
+  auto rootActor = Stage::GetCurrent().GetRootLayer();
+
+  auto cameraActor = CameraActor::New(targetSize);
+  float fov = Math::PI * 0.25f;
+  cameraActor.SetFieldOfView( fov );
+  cameraActor.SetNearClippingPlane( 1.0f );
+  cameraActor.SetAspectRatio( targetSize.width / targetSize.height );
+  cameraActor.SetType( Dali::Camera::FREE_LOOK );
+  cameraActor.SetPosition( 0.0f, 0.0f, ((targetSize.height * 0.5f) / tanf( fov * 0.5f ) ) );
+  cameraActor.SetParentOrigin(ParentOrigin::CENTER);
+  rootActor.Add(cameraActor);
+
+  RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
+
+  auto renderTask = taskList.CreateTask();
+  renderTask.SetRefreshRate(RenderTask::REFRESH_ONCE);
+  renderTask.SetSourceActor(inputActor);
+  renderTask.SetExclusive(true);
+
+  renderTask.SetInputEnabled(false);
+  renderTask.SetClearColor(Vector4(1.,0.,0.,1.));
+  renderTask.SetClearEnabled(true);
+  renderTask.SetCameraActor(cameraActor);
+
+  renderTask.SetFrameBuffer( fbo );
+}
+
+
+float CalcGaussianWeight(float x)
+{
+  const float BELL_CURVE_WIDTH( 1.5f );
+
+  return (1.0f / sqrt(2.0f * Math::PI * BELL_CURVE_WIDTH)) * exp(-(x * x) / (2.0f * BELL_CURVE_WIDTH * BELL_CURVE_WIDTH));
+}
+
+std::string GetSampleOffsetsPropertyName( unsigned int index )
+{
+  std::ostringstream oss;
+  oss << "uSampleOffsets[" << index << "]";
+  return oss.str();
+}
+
+std::string GetSampleWeightsPropertyName( unsigned int index )
+{
+  std::ostringstream oss;
+  oss << "uSampleWeights[" << index << "]";
+  return oss.str();
+}
+
+
+void SetShaderConstants(Actor actor, Direction direction, uint32_t numSamples, float downsampledWidth, float downsampledHeight)
+{
+  Vector2 *uvOffsets;
+  float ofs;
+  float *weights;
+  float w, totalWeights;
+  unsigned int i;
+
+  uvOffsets = new Vector2[numSamples + 1];
+  weights = new float[numSamples + 1];
+
+  totalWeights = weights[0] = CalcGaussianWeight(0);
+  uvOffsets[0].x = 0.0f;
+  uvOffsets[0].y = 0.0f;
+
+  for(i=0; i<numSamples >> 1; i++)
+  {
+    w = CalcGaussianWeight((float)(i + 1));
+    weights[(i << 1) + 1] = w;
+    weights[(i << 1) + 2] = w;
+    totalWeights += w * 2.0f;
+
+    // offset texture lookup to between texels, that way the bilinear filter in the texture hardware will average two samples with one lookup
+    ofs = ((float)(i << 1)) + 1.5f;
+
+    // get offsets from units of pixels into uv coordinates in [0..1]
+    float ofsX = ofs / downsampledWidth;
+    float ofsY = ofs / downsampledHeight;
+    uvOffsets[(i << 1) + 1].x = ofsX;
+    uvOffsets[(i << 1) + 1].y = ofsY;
+
+    uvOffsets[(i << 1) + 2].x = -ofsX;
+    uvOffsets[(i << 1) + 2].y = -ofsY;
+  }
+
+  for(i=0; i<numSamples; i++)
+  {
+    weights[i] /= totalWeights;
+  }
+
+  // set shader constants
+  Vector2 xAxis(1.0f, 0.0f);
+  Vector2 yAxis(0.0f, 1.0f);
+  for (i = 0; i < numSamples; ++i )
+  {
+    switch( direction )
+    {
+      case Direction::HORIZONTAL:
+      {
+        actor.RegisterProperty( GetSampleOffsetsPropertyName( i ), uvOffsets[ i ] * xAxis );
+        actor.RegisterProperty( GetSampleWeightsPropertyName( i ), weights[ i ] );
+        break;
+      }
+      case Direction::VERTICAL:
+      {
+        actor.RegisterProperty( GetSampleOffsetsPropertyName( i ), uvOffsets[ i ] * yAxis );
+        actor.RegisterProperty( GetSampleWeightsPropertyName( i ), weights[ i ] );
+        break;
+      }
+    }
+  }
+
+  delete[] uvOffsets;
+  delete[] weights;
+}
+
+} // namespace Util
diff --git a/examples/image-view-blur/utils.h b/examples/image-view-blur/utils.h
new file mode 100644 (file)
index 0000000..2059e6a
--- /dev/null
@@ -0,0 +1,49 @@
+#ifndef UTILS_H
+#define UTILS_H
+
+/*
+ * Copyright (c) 2018 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-toolkit/dali-toolkit.h>
+#include <string>
+#include <vector>
+
+namespace Utils
+{
+
+enum class Direction
+{
+  HORIZONTAL,
+  VERTICAL
+};
+
+std::string CreateEffectPassTexture( std::string inputUrl, std::vector<uint32_t>& fragShader,
+                                     Dali::Vector2 targetSize, Direction direction );
+Dali::Actor CreateEffectPassTexture( std::string inputUrl, std::vector<uint32_t>& fragShader,
+                                     Dali::Vector2 targetSize, Direction direction, Dali::FrameBuffer fb );
+Dali::Actor CreatePreview( const std::string& url, Dali::Vector2 targetSize, Dali::Vector3 parentOrigin,
+                           Dali::Vector3 labelOrigin, const std::string& label, bool copy );
+Dali::Actor CreatePreviewRenderTask( std::string url, Dali::Vector2 targetSize );
+Dali::Texture CreateRenderTask(Dali::Actor inputActor, Dali::Vector2 targetSize);
+void CreateRenderTask(Dali::Actor inputActor, Dali::Vector2 targetSize, Dali::FrameBuffer fbo);
+
+void SetShaderConstants(Dali::Actor actor, Direction direction, uint32_t numSamples,
+                        float downsampledWidth, float downsampledHeight);
+
+
+}
+
+#endif // UTILS_H