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