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