Merge "Fix resource ready state" into devel/master
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / shadow-view / shadow-view-impl.cpp
1 /*
2  * Copyright (c) 2020 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 "shadow-view-impl.h"
20
21 // EXTERNAL INCLUDES
22 #include <sstream>
23 #include <iomanip>
24 #include <dali/public-api/animation/constraint.h>
25 #include <dali/devel-api/common/stage.h>
26 #include <dali/public-api/object/type-registry.h>
27 #include <dali/public-api/object/type-registry-helper.h>
28 #include <dali/public-api/render-tasks/render-task-list.h>
29 #include <dali/public-api/rendering/shader.h>
30 #include <dali/integration-api/debug.h>
31
32 // INTERNAL INCLUDES
33 #include <dali-toolkit/public-api/visuals/visual-properties.h>
34 #include <dali-toolkit/internal/graphics/builtin-shader-extern-gen.h>
35 #include <dali-toolkit/internal/controls/control/control-renderers.h>
36 #include <dali-toolkit/internal/controls/shadow-view/shadow-view-impl.h>
37 #include <dali-toolkit/internal/filters/blur-two-pass-filter.h>
38 #include <dali-toolkit/internal/controls/control/control-data-impl.h>
39
40 // TODO:
41 // pixel format / size - set from JSON
42 // aspect ratio property needs to be able to be constrained also for cameras. (now do-able)
43 // default near clip value
44
45
46 /////////////////////////////////////////////////////////
47 // IMPLEMENTATION NOTES
48
49 // As the ShadowView actor changes size, the amount of pixels we need to blur changes. Therefore we need some way of doing this. However:-
50 // OnSetSize() does not get called when ShadowView object size is modified using a Constraint.
51 // OnSizeAnimation() only gets called once per AnimateTo/By() and if an Animation has N such calls then only the final one will end up being used. Therefore we can't use
52 // OnSizeAnimation() to alter render target sizes.
53 // To get around the above problems, we use fixed sized render targets, from the last SetSize() call (which calls OnSetSize()), then we adjust the internal cameras / actors
54 // to take account of the changed ShadowView object size, projecting to the unchanged render target sizes. This is done relative to the fixed render target / actor sizes
55 // by using constraints relative to the ShadowView actor size.
56
57 namespace Dali
58 {
59
60 namespace Toolkit
61 {
62
63 namespace Internal
64 {
65
66 namespace
67 {
68
69 using namespace Dali;
70
71 BaseHandle Create()
72 {
73   return Toolkit::ShadowView::New();
74 }
75
76 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::ShadowView, Toolkit::Control, Create )
77 DALI_TYPE_REGISTRATION_END()
78
79 const float BLUR_STRENGTH_DEFAULT = 1.0f;
80
81 const Vector3 DEFAULT_LIGHT_POSITION(300.0f, 250.0f, 600.0f);
82 const float DEFAULT_FIELD_OF_VIEW_RADIANS = Math::PI / 4.0f; // 45 degrees
83
84 const Vector4 DEFAULT_SHADOW_COLOR = Vector4(0.2f, 0.2f, 0.2f, 0.8f);
85
86 const char* const SHADER_LIGHT_CAMERA_PROJECTION_MATRIX_PROPERTY_NAME = "uLightCameraProjectionMatrix";
87 const char* const SHADER_LIGHT_CAMERA_VIEW_MATRIX_PROPERTY_NAME = "uLightCameraViewMatrix";
88 const char* const SHADER_SHADOW_COLOR_PROPERTY_NAME = "uShadowColor";
89 const char* const BLUR_STRENGTH_PROPERTY_NAME = "BlurStrengthProperty";
90 const char* const SHADOW_COLOR_PROPERTY_NAME = "ShadowColorProperty";
91
92 } // namespace
93
94 ShadowView::ShadowView( float downsampleWidthScale, float downsampleHeightScale )
95 : Control( ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) ),
96   mChildrenRoot(Actor::New()),
97   mCachedShadowColor(DEFAULT_SHADOW_COLOR),
98   mCachedBackgroundColor(DEFAULT_SHADOW_COLOR.r, DEFAULT_SHADOW_COLOR.g, DEFAULT_SHADOW_COLOR.b, 0.0f),
99   mBlurStrengthPropertyIndex(Property::INVALID_INDEX),
100   mShadowColorPropertyIndex(Property::INVALID_INDEX),
101   mDownsampleWidthScale(downsampleWidthScale),
102   mDownsampleHeightScale(downsampleHeightScale)
103 {
104 }
105
106 ShadowView::~ShadowView()
107 {
108 }
109
110 Toolkit::ShadowView ShadowView::New(float downsampleWidthScale, float downsampleHeightScale)
111 {
112   ShadowView* impl = new ShadowView(downsampleWidthScale, downsampleHeightScale);
113
114   Dali::Toolkit::ShadowView handle = Dali::Toolkit::ShadowView( *impl );
115
116   // Second-phase init of the implementation
117   // This can only be done after the CustomActor connection has been made...
118   impl->Initialize();
119
120   return handle;
121 }
122
123 void ShadowView::SetShadowPlaneBackground(Actor shadowPlaneBackground)
124 {
125   mShadowPlaneBg = shadowPlaneBackground;
126
127   mShadowPlane = Actor::New();
128   mShadowPlane.SetProperty( Actor::Property::NAME, "SHADOW_PLANE" );
129   mShadowPlane.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
130   mShadowPlane.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER );
131   Renderer shadowRenderer = CreateRenderer( SHADER_SHADOW_VIEW_RENDER_SHADER_VERT, SHADER_SHADOW_VIEW_RENDER_SHADER_FRAG,
132                                             Shader::Hint::OUTPUT_IS_TRANSPARENT,
133                                             Uint16Pair(20,20) );
134   TextureSet textureSet = shadowRenderer.GetTextures();
135   textureSet.SetTexture( 0u, mOutputFrameBuffer.GetColorTexture() );
136   mShadowPlane.AddRenderer( shadowRenderer );
137
138   SetShaderConstants();
139
140   // Rather than parent the shadow plane drawable and have constraints to move it to the same
141   // position, instead parent the shadow plane drawable on the shadow plane passed in.
142   mShadowPlaneBg.Add( mShadowPlane );
143   mShadowPlane.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
144   mShadowPlane.SetProperty( Actor::Property::POSITION_Z,  1.0f );
145
146   ConstrainCamera();
147
148   mShadowPlane.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
149
150   mBlurRootActor.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
151 }
152
153 void ShadowView::SetPointLight(Actor pointLight)
154 {
155   mPointLight = pointLight;
156
157   ConstrainCamera();
158 }
159
160 void ShadowView::SetPointLightFieldOfView(float fieldOfView)
161 {
162   mCameraActor.SetFieldOfView(fieldOfView);
163 }
164
165 void ShadowView::SetShadowColor(Vector4 color)
166 {
167   mCachedShadowColor = color;
168   mCachedBackgroundColor.r = color.r;
169   mCachedBackgroundColor.g = color.g;
170   mCachedBackgroundColor.b = color.b;
171
172   if( mShadowPlane )
173   {
174     mShadowPlane.SetProperty( mShadowColorPropertyIndex, mCachedShadowColor );
175   }
176   if(mRenderSceneTask)
177   {
178     mRenderSceneTask.SetClearColor( mCachedBackgroundColor );
179   }
180 }
181
182 void ShadowView::Activate()
183 {
184   DALI_ASSERT_ALWAYS( Self().GetProperty< bool >( Actor::Property::CONNECTED_TO_SCENE ) && "ShadowView should be on stage before calling Activate()\n" );
185
186   // make sure resources are allocated and start the render tasks processing
187   CreateRenderTasks();
188 }
189
190 void ShadowView::Deactivate()
191 {
192   DALI_ASSERT_ALWAYS( Self().GetProperty< bool >( Actor::Property::CONNECTED_TO_SCENE ) && "ShadowView should be on stage before calling Deactivate()\n" )
193
194   // stop render tasks processing
195   // Note: render target resources are automatically freed since we set the Image::Unused flag
196   RemoveRenderTasks();
197 }
198
199 ///////////////////////////////////////////////////////////
200 //
201 // Private methods
202 //
203
204 void ShadowView::OnInitialize()
205 {
206   // root actor to parent all user added actors. Used as source actor for shadow render task.
207   mChildrenRoot.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
208   mChildrenRoot.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
209
210   Vector2 stageSize = Stage::GetCurrent().GetSize();
211   mCameraActor = CameraActor::New(stageSize);
212
213   mCameraActor.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
214
215   // Target is constrained to point at the shadow plane origin
216   mCameraActor.SetNearClippingPlane( 1.0f );
217   mCameraActor.SetType( Dali::Camera::FREE_LOOK ); // Camera orientation constrained to point at shadow plane world position
218   mCameraActor.SetProperty( Actor::Property::ORIENTATION, Quaternion(Radian(Degree(180)), Vector3::YAXIS) );
219   mCameraActor.SetProperty( Actor::Property::POSITION, DEFAULT_LIGHT_POSITION );
220
221   // Create render targets needed for rendering from light's point of view
222   mSceneFromLightRenderTarget = FrameBuffer::New( stageSize.width, stageSize.height, FrameBuffer::Attachment::NONE );
223   Texture textureFromLight = Texture::New( TextureType::TEXTURE_2D, Pixel::RGBA8888, unsigned(stageSize.width), unsigned(stageSize.height) );
224   mSceneFromLightRenderTarget.AttachColorTexture( textureFromLight );
225
226   mOutputFrameBuffer = FrameBuffer::New( stageSize.width * 0.5f, stageSize.height * 0.5f, FrameBuffer::Attachment::NONE );
227   Texture outputTexture = Texture::New( TextureType::TEXTURE_2D, Pixel::RGBA8888, unsigned(stageSize.width * 0.5f), unsigned(stageSize.height * 0.5f) );
228   mOutputFrameBuffer.AttachColorTexture( outputTexture );
229
230   //////////////////////////////////////////////////////
231   // Connect to actor tree
232
233   Self().Add( mChildrenRoot );
234   Stage::GetCurrent().Add( mCameraActor );
235
236   mBlurFilter.SetRefreshOnDemand( false );
237   mBlurFilter.SetInputTexture( mSceneFromLightRenderTarget.GetColorTexture() );
238   mBlurFilter.SetOutputFrameBuffer( mOutputFrameBuffer );
239   mBlurFilter.SetSize( stageSize * 0.5f );
240   mBlurFilter.SetPixelFormat( Pixel::RGBA8888 );
241
242   mBlurRootActor = Actor::New();
243   mBlurRootActor.SetProperty( Actor::Property::NAME, "BLUR_ROOT_ACTOR" );
244
245   // Turn off inheritance to ensure filter renders properly
246   mBlurRootActor.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
247   mBlurRootActor.SetProperty( Actor::Property::INHERIT_POSITION, false );
248   mBlurRootActor.SetProperty( Actor::Property::INHERIT_ORIENTATION, false );
249   mBlurRootActor.SetProperty( Actor::Property::INHERIT_SCALE, false );
250   mBlurRootActor.SetProperty( Actor::Property::COLOR_MODE, USE_OWN_COLOR );
251
252   Self().Add( mBlurRootActor );
253
254   mBlurFilter.SetRootActor(mBlurRootActor);
255   mBlurFilter.SetBackgroundColor(Vector4::ZERO);
256
257   CustomActor self = Self();
258   // Register a property that the user can use to control the blur in the internal object
259   mBlurStrengthPropertyIndex = self.RegisterProperty(BLUR_STRENGTH_PROPERTY_NAME, BLUR_STRENGTH_DEFAULT);
260
261   Constraint blurStrengthConstraint = Constraint::New<float>( mBlurFilter.GetHandleForAnimateBlurStrength(), mBlurFilter.GetBlurStrengthPropertyIndex(), EqualToConstraint() );
262   blurStrengthConstraint.AddSource( Source( self, mBlurStrengthPropertyIndex) );
263   blurStrengthConstraint.Apply();
264
265   DevelControl::SetAccessibilityConstructor( Self(), []( Dali::Actor actor ) {
266     return std::unique_ptr< Dali::Accessibility::Accessible >(
267       new Control::Impl::AccessibleImpl( actor, Dali::Accessibility::Role::FILLER ) );
268   } );
269 }
270
271 void ShadowView::OnChildAdd( Actor& child )
272 {
273   if( child != mChildrenRoot && child != mBlurRootActor)
274   {
275     mChildrenRoot.Add( child );
276   }
277
278   Control::OnChildAdd( child );
279 }
280
281 void ShadowView::OnChildRemove( Actor& child )
282 {
283   mChildrenRoot.Remove( child );
284
285   Control::OnChildRemove( child );
286 }
287
288 void ShadowView::ConstrainCamera()
289 {
290   if( mPointLight && mShadowPlane )
291   {
292     // Constrain camera to look directly at center of shadow plane. (mPointLight position
293     // is under control of application, can't use transform inheritance)
294
295     Constraint cameraOrientationConstraint = Constraint::New<Quaternion> ( mCameraActor, Actor::Property::ORIENTATION, &LookAt );
296     cameraOrientationConstraint.AddSource( Source( mShadowPlane, Actor::Property::WORLD_POSITION ) );
297     cameraOrientationConstraint.AddSource( Source( mPointLight,  Actor::Property::WORLD_POSITION ) );
298     cameraOrientationConstraint.AddSource( Source( mShadowPlane, Actor::Property::WORLD_ORIENTATION ) );
299     cameraOrientationConstraint.Apply();
300
301     Constraint pointLightPositionConstraint = Constraint::New<Vector3>( mCameraActor, Actor::Property::POSITION, EqualToConstraint() );
302     pointLightPositionConstraint.AddSource( Source( mPointLight, Actor::Property::WORLD_POSITION ) );
303     pointLightPositionConstraint.Apply();
304   }
305 }
306
307 void ShadowView::CreateRenderTasks()
308 {
309   RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
310
311   // We want the first task to render the scene from the light
312   mRenderSceneTask = taskList.CreateTask();
313
314   mRenderSceneTask.SetCameraActor( mCameraActor );
315   mRenderSceneTask.SetSourceActor( mChildrenRoot );
316   mRenderSceneTask.SetFrameBuffer( mSceneFromLightRenderTarget );
317   mRenderSceneTask.SetInputEnabled( false );
318   mRenderSceneTask.SetClearEnabled( true );
319
320   // background color for render task should be the shadow color, but with alpha 0
321   // we don't want to blend the edges of the content with a BLACK at alpha 0, but
322   // the same shadow color at alpha 0.
323   mRenderSceneTask.SetClearColor( mCachedBackgroundColor );
324
325   mBlurFilter.Enable();
326 }
327
328 void ShadowView::RemoveRenderTasks()
329 {
330   RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
331
332   taskList.RemoveTask(mRenderSceneTask);
333   mRenderSceneTask.Reset();
334
335   mBlurFilter.Disable();
336 }
337
338 void ShadowView::SetShaderConstants()
339 {
340   Property::Index lightCameraProjectionMatrixPropertyIndex = mShadowPlane.RegisterProperty( SHADER_LIGHT_CAMERA_PROJECTION_MATRIX_PROPERTY_NAME, Matrix::IDENTITY );
341   Constraint projectionMatrixConstraint = Constraint::New<Dali::Matrix>( mShadowPlane, lightCameraProjectionMatrixPropertyIndex, EqualToConstraint() );
342   projectionMatrixConstraint.AddSource( Source( mCameraActor, CameraActor::Property::PROJECTION_MATRIX ) );
343   projectionMatrixConstraint.Apply();
344
345   Property::Index lightCameraViewMatrixPropertyIndex = mShadowPlane.RegisterProperty( SHADER_LIGHT_CAMERA_VIEW_MATRIX_PROPERTY_NAME, Matrix::IDENTITY );
346   Constraint viewMatrixConstraint = Constraint::New<Dali::Matrix>( mShadowPlane, lightCameraViewMatrixPropertyIndex, EqualToConstraint() );
347   viewMatrixConstraint.AddSource( Source( mCameraActor, CameraActor::Property::VIEW_MATRIX ) );
348   viewMatrixConstraint.Apply();
349
350   mShadowColorPropertyIndex = mShadowPlane.RegisterProperty( SHADER_SHADOW_COLOR_PROPERTY_NAME, mCachedShadowColor );
351 }
352
353 } // namespace Internal
354
355 } // namespace Toolkit
356
357 } // namespace Dali