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