(Visuals) Added visual indices
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / bloom-view / bloom-view-impl.cpp
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include "bloom-view-impl.h"
20
21 // EXTERNAL INCLUDES
22 #include <sstream>
23 #include <iomanip>
24 #include <dali/public-api/animation/constraint.h>
25 #include <dali/public-api/animation/constraints.h>
26 #include <dali/public-api/common/stage.h>
27 #include <dali/public-api/object/property-map.h>
28 #include <dali/public-api/object/type-registry.h>
29 #include <dali/public-api/object/type-registry-helper.h>
30 #include <dali/public-api/render-tasks/render-task-list.h>
31 #include <dali/public-api/rendering/renderer.h>
32 #include <dali/devel-api/images/texture-set-image.h>
33
34 // INTERNAL INCLUDES
35 #include <dali-toolkit/public-api/controls/gaussian-blur-view/gaussian-blur-view.h>
36 #include <dali-toolkit/public-api/visuals/visual-properties.h>
37 #include <dali-toolkit/devel-api/controls/bloom-view/bloom-view.h>
38 #include <dali-toolkit/internal/controls/gaussian-blur-view/gaussian-blur-view-impl.h>
39
40 namespace Dali
41 {
42
43 namespace Toolkit
44 {
45
46 namespace Internal
47 {
48
49 namespace
50 {
51
52 using namespace Dali;
53
54 BaseHandle Create()
55 {
56   return Toolkit::BloomView::New();
57 }
58
59 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::BloomView, Toolkit::Control, Create )
60 DALI_TYPE_REGISTRATION_END()
61
62 // default parameters
63 const float BLOOM_THRESHOLD_DEFAULT = 0.25f;
64 const float BLOOM_BLUR_STRENGTH_DEFAULT = 1.0f;
65 const float BLOOM_INTENSITY_DEFAULT = 1.0f;
66 const float IMAGE_INTENSITY_DEFAULT = 1.0f;
67 const float BLOOM_SATURATION_DEFAULT = 1.0f;
68 const float IMAGE_SATURATION_DEFAULT = 1.0f;
69
70 // gaussian blur
71 const unsigned int BLOOM_GAUSSIAN_BLUR_VIEW_DEFAULT_NUM_SAMPLES = 5;
72 const float BLOOM_GAUSSIAN_BLUR_VIEW_DEFAULT_BLUR_BELL_CURVE_WIDTH = 1.5f;
73 const Pixel::Format BLOOM_GAUSSIAN_BLUR_VIEW_DEFAULT_RENDER_TARGET_PIXEL_FORMAT = Pixel::RGBA8888;
74 const float BLOOM_GAUSSIAN_BLUR_VIEW_DEFAULT_BLUR_FADE_IN = 1.0f;                                       // default, fully blurred
75 const float BLOOM_GAUSSIAN_BLUR_VIEW_DEFAULT_DOWNSAMPLE_WIDTH_SCALE = 0.5f;
76 const float BLOOM_GAUSSIAN_BLUR_VIEW_DEFAULT_DOWNSAMPLE_HEIGHT_SCALE = 0.5f;
77
78 const float ARBITRARY_FIELD_OF_VIEW = Math::PI / 4.0f;
79
80 const char* const BLOOM_BLUR_STRENGTH_PROPERTY_NAME = "BlurStrengthProperty";
81 const char* const BLOOM_THRESHOLD_PROPERTY_NAME = "uBloomThreshold";
82 const char* const RECIP_ONE_MINUS_BLOOM_THRESHOLD_PROPERTY_NAME = "uRecipOneMinusBloomThreshold";
83 const char* const BLOOM_INTENSITY_PROPERTY_NAME = "uBloomIntensity";
84 const char* const BLOOM_SATURATION_PROPERTY_NAME = "uBloomSaturation";
85 const char* const IMAGE_INTENSITY_PROPERTY_NAME = "uImageIntensity";
86 const char* const IMAGE_SATURATION_PROPERTY_NAME = "uImageSaturation";
87
88 ///////////////////////////////////////////////////////
89 //
90 // Bloom shaders
91 //
92
93 const char* const BLOOM_EXTRACT_FRAGMENT_SOURCE =
94   "varying mediump vec2 vTexCoord;\n"
95   "uniform sampler2D sTexture;\n"
96   "uniform lowp vec4 uColor;\n"
97   "uniform mediump float uBloomThreshold;\n"
98   "uniform mediump float uRecipOneMinusBloomThreshold;\n"
99   "void main()\n"
100   "{\n"
101   "  mediump vec4 col;\n"
102   "  col = texture2D(sTexture, vTexCoord);\n"
103   "  col = (col - uBloomThreshold) * uRecipOneMinusBloomThreshold;\n" // remove intensities lower than the thresold and remap intensities above the threshold to [0..1]
104   "  gl_FragColor = clamp(col, 0.0, 1.0);\n"
105   "}\n";
106
107 const char* const COMPOSITE_FRAGMENT_SOURCE =
108   "precision mediump float;\n"
109   "varying mediump vec2 vTexCoord;\n"
110   "uniform sampler2D sTexture;\n"
111   "uniform sampler2D sEffect;\n"
112   "uniform lowp vec4 uColor;\n"
113   "uniform float uBloomIntensity;\n"
114   "uniform float uImageIntensity;\n"
115   "uniform float uBloomSaturation;\n"
116   "uniform float uImageSaturation;\n"
117
118   "vec4 ChangeSaturation(vec4 col, float sat)\n"
119   "{\n"
120   "  float grey = dot(col.rgb, vec3(0.3, 0.6, 0.1));\n"
121   "  return mix(vec4(grey, grey, grey, 1.0), col, sat);\n"
122   "}\n"
123
124   "void main()\n"
125   "{\n"
126   "  mediump vec4 image;\n"
127   "  mediump vec4 bloom;\n"
128   "  image = texture2D(sTexture, vTexCoord);\n"
129   "  bloom = texture2D(sEffect, vTexCoord);\n"
130   "  image = ChangeSaturation(image, uImageSaturation) * uImageIntensity;\n"
131   "  bloom = ChangeSaturation(bloom, uBloomSaturation) * uBloomIntensity;\n"
132   "  image *= 1.0 - clamp(bloom, 0.0, 1.0);\n" // darken base where bloom is strong, to prevent excessive burn-out of result
133   "  gl_FragColor = image + bloom;\n"
134   "}\n";
135
136 } // namespace
137
138
139
140 BloomView::BloomView()
141   : Control( ControlBehaviour( ACTOR_BEHAVIOUR_NONE ) )
142   , mBlurNumSamples(BLOOM_GAUSSIAN_BLUR_VIEW_DEFAULT_NUM_SAMPLES)
143   , mBlurBellCurveWidth(BLOOM_GAUSSIAN_BLUR_VIEW_DEFAULT_BLUR_BELL_CURVE_WIDTH)
144   , mPixelFormat(BLOOM_GAUSSIAN_BLUR_VIEW_DEFAULT_RENDER_TARGET_PIXEL_FORMAT)
145   , mDownsampleWidthScale(BLOOM_GAUSSIAN_BLUR_VIEW_DEFAULT_DOWNSAMPLE_WIDTH_SCALE)
146   , mDownsampleHeightScale(BLOOM_GAUSSIAN_BLUR_VIEW_DEFAULT_DOWNSAMPLE_HEIGHT_SCALE)
147   , mDownsampledWidth( 0.0f )
148   , mDownsampledHeight( 0.0f )
149   , mTargetSize(Vector2::ZERO)
150   , mLastSize(Vector2::ZERO)
151   , mChildrenRoot(Actor::New())
152   , mInternalRoot(Actor::New() )
153   , mBloomThresholdPropertyIndex(Property::INVALID_INDEX)
154   , mBlurStrengthPropertyIndex(Property::INVALID_INDEX)
155   , mBloomIntensityPropertyIndex(Property::INVALID_INDEX)
156   , mBloomSaturationPropertyIndex(Property::INVALID_INDEX)
157   , mImageIntensityPropertyIndex(Property::INVALID_INDEX)
158   , mImageSaturationPropertyIndex(Property::INVALID_INDEX)
159   , mActivated( false )
160 {
161 }
162
163 BloomView::BloomView( const unsigned int blurNumSamples, const float blurBellCurveWidth, const Pixel::Format renderTargetPixelFormat,
164                                     const float downsampleWidthScale, const float downsampleHeightScale)
165   : Control( ControlBehaviour( ACTOR_BEHAVIOUR_NONE ) )
166   , mBlurNumSamples(blurNumSamples)
167   , mBlurBellCurveWidth(blurBellCurveWidth)
168   , mPixelFormat(renderTargetPixelFormat)
169   , mDownsampleWidthScale(downsampleWidthScale)
170   , mDownsampleHeightScale(downsampleHeightScale)
171   , mDownsampledWidth( 0.0f )
172   , mDownsampledHeight( 0.0f )
173   , mTargetSize(Vector2::ZERO)
174   , mLastSize(Vector2::ZERO)
175   , mChildrenRoot(Actor::New())
176   , mInternalRoot(Actor::New())
177   , mBloomThresholdPropertyIndex(Property::INVALID_INDEX)
178   , mBlurStrengthPropertyIndex(Property::INVALID_INDEX)
179   , mBloomIntensityPropertyIndex(Property::INVALID_INDEX)
180   , mBloomSaturationPropertyIndex(Property::INVALID_INDEX)
181   , mImageIntensityPropertyIndex(Property::INVALID_INDEX)
182   , mImageSaturationPropertyIndex(Property::INVALID_INDEX)
183   , mActivated( false )
184 {
185 }
186
187 BloomView::~BloomView()
188 {
189 }
190
191 Toolkit::BloomView BloomView::New()
192 {
193   BloomView* impl = new BloomView();
194
195   Dali::Toolkit::BloomView handle = Dali::Toolkit::BloomView( *impl );
196
197   // Second-phase init of the implementation
198   // This can only be done after the CustomActor connection has been made...
199   impl->Initialize();
200
201   return handle;
202 }
203
204 Toolkit::BloomView BloomView::New(const unsigned int blurNumSamples, const float blurBellCurveWidth, const Pixel::Format renderTargetPixelFormat,
205                                                 const float downsampleWidthScale, const float downsampleHeightScale)
206 {
207   BloomView* impl = new BloomView( blurNumSamples, blurBellCurveWidth, renderTargetPixelFormat, downsampleWidthScale, downsampleHeightScale);
208
209   Dali::Toolkit::BloomView handle = Dali::Toolkit::BloomView( *impl );
210
211   // Second-phase init of the implementation
212   // This can only be done after the CustomActor connection has been made...
213   impl->Initialize();
214
215   return handle;
216 }
217
218 ///////////////////////////////////////////////////////////
219 //
220 // Private methods
221 //
222
223 void BloomView::OnInitialize()
224 {
225   // root actor to parent all user added actors, needed to allow us to set that subtree as exclusive for our child render task
226   mChildrenRoot.SetParentOrigin( ParentOrigin::CENTER );
227   mInternalRoot.SetParentOrigin( ParentOrigin::CENTER );
228
229   //////////////////////////////////////////////////////
230   // Create actors
231
232   // Create an image view for rendering from the scene texture to the bloom texture
233   mBloomExtractImageView = Toolkit::ImageView::New();
234   mBloomExtractImageView.SetParentOrigin( ParentOrigin::CENTER );
235
236   // Create an image view for compositing the result (scene and bloom textures) to output
237   mCompositeImageView = Toolkit::ImageView::New();
238   mCompositeImageView.SetParentOrigin( ParentOrigin::CENTER );
239
240   // Create an image view for holding final result, i.e. the blurred image. This will get rendered to screen later, via default / user render task
241   mTargetImageView = Toolkit::ImageView::New();
242   mTargetImageView.SetParentOrigin( ParentOrigin::CENTER );
243
244   // Create the Gaussian Blur object + render tasks
245   // Note that we use mBloomExtractTarget as the source image and also re-use this as the gaussian blur final render target. This saves the gaussian blur code from creating it
246   // render targets etc internally, so we make better use of resources
247   // Note, this also internally creates the render tasks used by the Gaussian blur, this must occur after the bloom extraction and before the compositing
248   mGaussianBlurView = Dali::Toolkit::GaussianBlurView::New(mBlurNumSamples, mBlurBellCurveWidth, mPixelFormat, mDownsampleWidthScale, mDownsampleHeightScale, true);
249   mGaussianBlurView.SetParentOrigin( ParentOrigin::CENTER );
250
251
252   //////////////////////////////////////////////////////
253   // Create cameras for the renders corresponding to the (potentially downsampled) render targets' size
254   mRenderDownsampledCamera = CameraActor::New();
255   mRenderDownsampledCamera.SetParentOrigin(ParentOrigin::CENTER);
256   mRenderDownsampledCamera.SetInvertYAxis( true );
257
258   mRenderFullSizeCamera = CameraActor::New();
259   mRenderFullSizeCamera.SetParentOrigin(ParentOrigin::CENTER);
260   mRenderFullSizeCamera.SetInvertYAxis( true );
261
262
263   ////////////////////////////////
264   // Connect to actor tree
265   Self().Add( mChildrenRoot );
266   Self().Add( mInternalRoot );
267   mInternalRoot.Add( mBloomExtractImageView );
268   mInternalRoot.Add( mGaussianBlurView );
269   mInternalRoot.Add( mCompositeImageView );
270   mInternalRoot.Add( mTargetImageView );
271   mInternalRoot.Add( mRenderDownsampledCamera );
272   mInternalRoot.Add( mRenderFullSizeCamera );
273
274   // bind properties for / set shader constants to defaults
275   SetupProperties();
276 }
277
278 void BloomView::OnSizeSet(const Vector3& targetSize)
279 {
280   Control::OnSizeSet( targetSize );
281
282   mTargetSize = Vector2(targetSize);
283   mChildrenRoot.SetSize(targetSize);
284   mCompositeImageView.SetSize(targetSize);
285   mTargetImageView.SetSize(targetSize);
286
287   // Children render camera must move when GaussianBlurView object is
288   // resized. This is since we cannot change render target size - so we need
289   // to remap the child actors' rendering accordingly so they still exactly
290   // fill the render target. Note that this means the effective resolution of
291   // the child render changes as the GaussianBlurView object changes size,
292   // this is the trade off for not being able to modify render target size
293   // Change camera z position based on GaussianBlurView actor height
294   float cameraPosConstraintScale = 0.5f / tanf(ARBITRARY_FIELD_OF_VIEW * 0.5f);
295   mRenderFullSizeCamera.SetZ( mTargetSize.height * cameraPosConstraintScale);
296
297   // if we have already activated the blur, need to update render target sizes now to reflect the new size of this actor
298   if(mActivated)
299   {
300     Deactivate();
301     Activate();
302   }
303 }
304
305 void BloomView::OnChildAdd( Actor& child )
306 {
307   Control::OnChildAdd( child );
308
309   if( child != mChildrenRoot && child != mInternalRoot)
310   {
311     mChildrenRoot.Add( child );
312   }
313 }
314
315 void BloomView::OnChildRemove( Actor& child )
316 {
317   mChildrenRoot.Remove( child );
318
319   Control::OnChildRemove( child );
320 }
321
322 void BloomView::AllocateResources()
323 {
324   // size of render targets etc is based on the size of this actor, ignoring z
325   if(mTargetSize != mLastSize || !mActivated)
326   {
327     mLastSize = mTargetSize;
328
329     // get size of downsampled render targets
330     mDownsampledWidth = mTargetSize.width * mDownsampleWidthScale;
331     mDownsampledHeight = mTargetSize.height * mDownsampleHeightScale;
332
333
334     //////////////////////////////////////////////////////
335     // Create cameras
336
337     // Create and place a camera for the renders corresponding to the (potentially downsampled) render targets' size
338     mRenderDownsampledCamera.SetFieldOfView(ARBITRARY_FIELD_OF_VIEW);
339     // TODO: how do we pick a reasonable value for near clip? Needs to relate to normal camera the user renders with, but we don't have a handle on it
340     mRenderDownsampledCamera.SetNearClippingPlane(1.0f);
341     mRenderDownsampledCamera.SetAspectRatio(mDownsampledWidth / mDownsampledHeight);
342     mRenderDownsampledCamera.SetType(Dali::Camera::FREE_LOOK); // camera orientation based solely on actor
343
344     mRenderDownsampledCamera.SetPosition(0.0f, 0.0f, ((mDownsampledHeight * 0.5f) / tanf(ARBITRARY_FIELD_OF_VIEW * 0.5f)));
345
346     // Create and place a camera for the children render, corresponding to its render target size
347     mRenderFullSizeCamera.SetFieldOfView(ARBITRARY_FIELD_OF_VIEW);
348     // TODO: how do we pick a reasonable value for near clip? Needs to relate to normal camera the user renders with, but we don't have a handle on it
349     mRenderFullSizeCamera.SetNearClippingPlane(1.0f);
350     mRenderFullSizeCamera.SetAspectRatio(mTargetSize.width / mTargetSize.height);
351     mRenderFullSizeCamera.SetType(Dali::Camera::FREE_LOOK); // camera orientation based solely on actor
352
353     float cameraPosConstraintScale = 0.5f / tanf(ARBITRARY_FIELD_OF_VIEW * 0.5f);
354     mRenderFullSizeCamera.SetPosition(0.0f, 0.0f, mTargetSize.height * cameraPosConstraintScale);
355
356     //////////////////////////////////////////////////////
357     // Pass size change onto GaussianBlurView, so it matches
358     mGaussianBlurView.SetSize(mTargetSize);
359     GetImpl(mGaussianBlurView).AllocateResources();
360
361
362     //////////////////////////////////////////////////////
363     // Create render targets
364
365     // create off screen buffer of new size to render our child actors to
366     mRenderTargetForRenderingChildren = FrameBufferImage::New( mTargetSize.width, mTargetSize.height, mPixelFormat, Dali::Image::UNUSED );
367     mBloomExtractTarget = FrameBufferImage::New( mDownsampledWidth, mDownsampledHeight, mPixelFormat, Dali::Image::UNUSED );
368     FrameBufferImage mBlurExtractTarget = FrameBufferImage::New( mDownsampledWidth, mDownsampledHeight, mPixelFormat, Dali::Image::UNUSED );
369     mOutputRenderTarget = FrameBufferImage::New( mTargetSize.width, mTargetSize.height, mPixelFormat, Dali::Image::UNUSED);
370
371
372     //////////////////////////////////////////////////////
373     // Point actors and render tasks at new render targets
374
375     mBloomExtractImageView.SetImage( mRenderTargetForRenderingChildren );
376     mBloomExtractImageView.SetSize(mDownsampledWidth, mDownsampledHeight); // size needs to match render target
377     // Create shader used for extracting the bright parts of an image
378     Property::Map customShader;
379     customShader[ Toolkit::Visual::Shader::Property::FRAGMENT_SHADER ] = BLOOM_EXTRACT_FRAGMENT_SOURCE;
380     Property::Map visualMap;
381     visualMap.Insert( Toolkit::Visual::Property::SHADER, customShader );
382     mBloomExtractImageView.SetProperty( Toolkit::ImageView::Property::IMAGE, visualMap );
383
384     // set GaussianBlurView to blur our extracted bloom
385     mGaussianBlurView.SetUserImageAndOutputRenderTarget(mBloomExtractTarget, mBlurExtractTarget);
386
387     // use the completed blur in the first buffer and composite with the original child actors render
388     mCompositeImageView.SetImage( mRenderTargetForRenderingChildren );
389     // Create shader used to composite bloom and original image to output render target
390     customShader[ Toolkit::Visual::Shader::Property::FRAGMENT_SHADER ] = COMPOSITE_FRAGMENT_SOURCE;
391     visualMap[ Toolkit::Visual::Property::SHADER ] = customShader;
392     mCompositeImageView.SetProperty( Toolkit::ImageView::Property::IMAGE, visualMap );
393     TextureSet textureSet = mCompositeImageView.GetRendererAt(0).GetTextures();
394     TextureSetImage( textureSet, 1u, mBlurExtractTarget );
395
396     // set up target actor for rendering result, i.e. the blurred image
397     mTargetImageView.SetImage(mOutputRenderTarget);
398   }
399 }
400
401 void BloomView::CreateRenderTasks()
402 {
403   RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
404
405   // create render task to render our child actors to offscreen buffer
406   mRenderChildrenTask = taskList.CreateTask();
407   mRenderChildrenTask.SetSourceActor( mChildrenRoot );
408   mRenderChildrenTask.SetExclusive(true);
409   mRenderChildrenTask.SetInputEnabled( false );
410   mRenderChildrenTask.SetClearEnabled( true );
411   mRenderChildrenTask.SetCameraActor(mRenderFullSizeCamera); // use camera that covers render target exactly
412   mRenderChildrenTask.SetTargetFrameBuffer( mRenderTargetForRenderingChildren );
413
414   // Extract the bright part of the image and render to a new buffer. Downsampling also occurs at this stage to save pixel fill, if it is set up.
415   mBloomExtractTask = taskList.CreateTask();
416   mBloomExtractTask.SetSourceActor( mBloomExtractImageView );
417   mBloomExtractTask.SetExclusive(true);
418   mBloomExtractTask.SetInputEnabled( false );
419   mBloomExtractTask.SetClearEnabled( true );
420   mBloomExtractTask.SetCameraActor(mRenderDownsampledCamera);
421   mBloomExtractTask.SetTargetFrameBuffer( mBloomExtractTarget );
422
423   // GaussianBlurView tasks must be created here, so they are executed in the correct order with respect to BloomView tasks
424   GetImpl(mGaussianBlurView).CreateRenderTasks();
425
426   // Use an image view displaying the children render and composite it with the blurred bloom buffer, targeting the output
427   mCompositeTask = taskList.CreateTask();
428   mCompositeTask.SetSourceActor( mCompositeImageView );
429   mCompositeTask.SetExclusive(true);
430   mCompositeTask.SetInputEnabled( false );
431   mCompositeTask.SetClearEnabled( true );
432   mCompositeTask.SetCameraActor(mRenderFullSizeCamera);
433   mCompositeTask.SetTargetFrameBuffer( mOutputRenderTarget );
434 }
435
436 void BloomView::RemoveRenderTasks()
437 {
438   RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
439
440   taskList.RemoveTask(mRenderChildrenTask);
441   taskList.RemoveTask(mBloomExtractTask);
442
443   GetImpl(mGaussianBlurView).RemoveRenderTasks();
444
445   taskList.RemoveTask(mCompositeTask);
446 }
447
448 void BloomView::Activate()
449 {
450   // make sure resources are allocated and start the render tasks processing
451   AllocateResources();
452   CreateRenderTasks();
453   mActivated = true;
454 }
455
456 void BloomView::Deactivate()
457 {
458   // stop render tasks processing
459   // Note: render target resources are automatically freed since we set the Image::Unused flag
460   RemoveRenderTasks();
461   mRenderTargetForRenderingChildren.Reset();
462   mBloomExtractTarget.Reset();
463   mOutputRenderTarget.Reset();
464   mActivated = false;
465 }
466
467 /**
468  * RecipOneMinusConstraint
469  *
470  * f(current, property) = property
471  */
472 struct RecipOneMinusConstraint
473 {
474   RecipOneMinusConstraint(){}
475
476   void operator()( float& current, const PropertyInputContainer& inputs )
477   {
478     current = 1.0f / ( 1.0f - inputs[0]->GetFloat() );
479   }
480 };
481
482 // create properties and constraints to tie internal shader etc settings to BloomView object. User can therefore animate / set them via BloomView object without knowing about
483 // internal implementation classes
484 void BloomView::SetupProperties()
485 {
486   CustomActor self = Self();
487
488
489   ///////////////////////////////////////////
490   // bloom threshold
491
492   // set defaults, makes sure properties are registered with shader
493   mBloomExtractImageView.RegisterProperty( BLOOM_THRESHOLD_PROPERTY_NAME, BLOOM_THRESHOLD_DEFAULT );
494   mBloomExtractImageView.RegisterProperty( RECIP_ONE_MINUS_BLOOM_THRESHOLD_PROPERTY_NAME, 1.0f / (1.0f - BLOOM_THRESHOLD_DEFAULT) );
495
496   // Register a property that the user can control to change the bloom threshold
497   mBloomThresholdPropertyIndex = self.RegisterProperty(BLOOM_THRESHOLD_PROPERTY_NAME, BLOOM_THRESHOLD_DEFAULT);
498   Property::Index shaderBloomThresholdPropertyIndex = mBloomExtractImageView.GetPropertyIndex(BLOOM_THRESHOLD_PROPERTY_NAME);
499   Constraint bloomThresholdConstraint = Constraint::New<float>( mBloomExtractImageView, shaderBloomThresholdPropertyIndex, EqualToConstraint());
500   bloomThresholdConstraint.AddSource( Source(self, mBloomThresholdPropertyIndex) );
501   bloomThresholdConstraint.Apply();
502
503   // precalc 1.0 / (1.0 - threshold) on CPU to save shader insns, using constraint to tie to the normal threshold property
504   Property::Index shaderRecipOneMinusBloomThresholdPropertyIndex = mBloomExtractImageView.GetPropertyIndex(RECIP_ONE_MINUS_BLOOM_THRESHOLD_PROPERTY_NAME);
505   Constraint thresholdConstraint = Constraint::New<float>( mBloomExtractImageView, shaderRecipOneMinusBloomThresholdPropertyIndex, RecipOneMinusConstraint());
506   thresholdConstraint.AddSource( LocalSource(shaderBloomThresholdPropertyIndex) );
507   thresholdConstraint.Apply();
508
509
510   ////////////////////////////////////////////
511   // bloom strength
512
513   // Register a property that the user can control to fade the blur in / out via internal GaussianBlurView object
514   mBlurStrengthPropertyIndex = self.RegisterProperty(BLOOM_BLUR_STRENGTH_PROPERTY_NAME, BLOOM_BLUR_STRENGTH_DEFAULT);
515   Constraint blurStrengthConstraint = Constraint::New<float>( mGaussianBlurView, mGaussianBlurView.GetBlurStrengthPropertyIndex(), EqualToConstraint());
516   blurStrengthConstraint.AddSource( Source(self, mBlurStrengthPropertyIndex) );
517   blurStrengthConstraint.Apply();
518
519
520   ////////////////////////////////////////////
521   // bloom intensity
522
523   // Register a property that the user can control to fade the bloom intensity via internally hidden shader
524   mBloomIntensityPropertyIndex = self.RegisterProperty(BLOOM_INTENSITY_PROPERTY_NAME, BLOOM_INTENSITY_DEFAULT);
525   mCompositeImageView.RegisterProperty( BLOOM_INTENSITY_PROPERTY_NAME, BLOOM_INTENSITY_DEFAULT );
526   Property::Index shaderBloomIntensityPropertyIndex = mCompositeImageView.GetPropertyIndex(BLOOM_INTENSITY_PROPERTY_NAME);
527   Constraint bloomIntensityConstraint = Constraint::New<float>( mCompositeImageView, shaderBloomIntensityPropertyIndex, EqualToConstraint());
528   bloomIntensityConstraint.AddSource( Source(self, mBloomIntensityPropertyIndex) );
529   bloomIntensityConstraint.Apply();
530
531
532   ////////////////////////////////////////////
533   // bloom saturation
534
535   // Register a property that the user can control to fade the bloom saturation via internally hidden shader
536   mBloomSaturationPropertyIndex = self.RegisterProperty(BLOOM_SATURATION_PROPERTY_NAME, BLOOM_SATURATION_DEFAULT);
537   mCompositeImageView.RegisterProperty( BLOOM_SATURATION_PROPERTY_NAME, BLOOM_SATURATION_DEFAULT );
538   Property::Index shaderBloomSaturationPropertyIndex = mCompositeImageView.GetPropertyIndex(BLOOM_SATURATION_PROPERTY_NAME);
539   Constraint bloomSaturationConstraint = Constraint::New<float>( mCompositeImageView, shaderBloomSaturationPropertyIndex, EqualToConstraint());
540   bloomSaturationConstraint.AddSource( Source(self, mBloomSaturationPropertyIndex) );
541   bloomSaturationConstraint.Apply();
542
543
544   ////////////////////////////////////////////
545   // image intensity
546
547   // Register a property that the user can control to fade the image intensity via internally hidden shader
548   mImageIntensityPropertyIndex = self.RegisterProperty(IMAGE_INTENSITY_PROPERTY_NAME, IMAGE_INTENSITY_DEFAULT);
549   mCompositeImageView.RegisterProperty( IMAGE_INTENSITY_PROPERTY_NAME, IMAGE_INTENSITY_DEFAULT );
550   Property::Index shaderImageIntensityPropertyIndex = mCompositeImageView.GetPropertyIndex(IMAGE_INTENSITY_PROPERTY_NAME);
551   Constraint imageIntensityConstraint = Constraint::New<float>( mCompositeImageView, shaderImageIntensityPropertyIndex, EqualToConstraint());
552   imageIntensityConstraint.AddSource( Source(self, mImageIntensityPropertyIndex) );
553   imageIntensityConstraint.Apply();
554
555
556   ////////////////////////////////////////////
557   // image saturation
558
559   // Register a property that the user can control to fade the image saturation via internally hidden shader
560   mImageSaturationPropertyIndex = self.RegisterProperty(IMAGE_SATURATION_PROPERTY_NAME, IMAGE_SATURATION_DEFAULT);
561   mCompositeImageView.RegisterProperty( IMAGE_SATURATION_PROPERTY_NAME, IMAGE_SATURATION_DEFAULT );
562   Property::Index shaderImageSaturationPropertyIndex = mCompositeImageView.GetPropertyIndex(IMAGE_SATURATION_PROPERTY_NAME);
563   Constraint imageSaturationConstraint = Constraint::New<float>( mCompositeImageView, shaderImageSaturationPropertyIndex, EqualToConstraint());
564   imageSaturationConstraint.AddSource( Source(self, mImageSaturationPropertyIndex) );
565   imageSaturationConstraint.Apply();
566 }
567
568 } // namespace Internal
569
570 } // namespace Toolkit
571
572 } // namespace Dali