Changes following deprecation of position inheritance modes
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / shadow-view / shadow-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 "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/public-api/common/stage.h>
26 #include <dali/public-api/object/type-registry.h>
27 #include <dali/devel-api/object/type-registry-helper.h>
28 #include <dali/public-api/render-tasks/render-task-list.h>
29 #include <dali/integration-api/debug.h>
30
31 // INTERNAL INCLUDES
32 #include <dali-toolkit/internal/controls/shadow-view/shadow-view-impl.h>
33 #include <dali-toolkit/internal/filters/blur-two-pass-filter.h>
34
35 // TODO:
36 // pixel format / size - set from JSON
37 // aspect ratio property needs to be able to be constrained also for cameras. (now do-able)
38 // default near clip value
39 // mChildrenRoot Add()/Remove() overloads - better solution
40
41
42 /////////////////////////////////////////////////////////
43 // IMPLEMENTATION NOTES
44
45 // As the ShadowView actor changes size, the amount of pixels we need to blur changes. Therefore we need some way of doing this. However:-
46 // OnSetSize() does not get called when ShadowView object size is modified using a Constraint.
47 // 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
48 // OnSizeAnimation() to alter render target sizes.
49 // 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
50 // 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
51 // by using constraints relative to the ShadowView actor size.
52
53 namespace Dali
54 {
55
56 namespace Toolkit
57 {
58
59 namespace Internal
60 {
61
62 namespace
63 {
64
65 using namespace Dali;
66
67 BaseHandle Create()
68 {
69   return Toolkit::ShadowView::New();
70 }
71
72 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::ShadowView, Toolkit::Control, Create )
73 DALI_TYPE_REGISTRATION_END()
74
75 const float BLUR_STRENGTH_DEFAULT = 1.0f;
76
77 const Vector3 DEFAULT_LIGHT_POSITION(300.0f, 250.0f, 600.0f);
78 const float DEFAULT_FIELD_OF_VIEW_RADIANS = Math::PI / 4.0f; // 45 degrees
79
80 const Vector4 DEFAULT_SHADOW_COLOR = Vector4(0.2f, 0.2f, 0.2f, 0.8f);
81
82 const char* const SHADER_LIGHT_CAMERA_PROJECTION_MATRIX_PROPERTY_NAME = "uLightCameraProjectionMatrix";
83 const char* const SHADER_LIGHT_CAMERA_VIEW_MATRIX_PROPERTY_NAME = "uLightCameraViewMatrix";
84 const char* const SHADER_SHADOW_COLOR_PROPERTY_NAME = "uShadowColor";
85 const char* const BLUR_STRENGTH_PROPERTY_NAME = "BlurStrengthProperty";
86 const char* const SHADOW_COLOR_PROPERTY_NAME = "ShadowColorProperty";
87
88 const char* const RENDER_SHADOW_VERTEX_SOURCE =
89
90   " attribute mediump vec2 aPosition;\n"
91   " uniform mediump mat4 uMvpMatrix;\n"
92   " uniform mediump mat4 uModelMatrix;\n"
93   " uniform vec3 uSize;\n"
94   " varying vec2 vTexCoord;\n"
95
96   " uniform mediump mat4 uLightCameraProjectionMatrix;\n"
97   " uniform mediump mat4 uLightCameraViewMatrix;\n"
98   "\n"
99   "void main()\n"
100   "{\n"
101     "  mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);\n"
102     "  vertexPosition.xyz *= uSize;\n"
103     "  gl_Position = uMvpMatrix * vertexPosition;\n"
104     "  vec4 textureCoords = uLightCameraProjectionMatrix * uLightCameraViewMatrix * uModelMatrix  * vertexPosition;\n"
105     "  vTexCoord = 0.5 + 0.5 * (textureCoords.xy/textureCoords.w);\n"
106   "}\n";
107
108 const char* const RENDER_SHADOW_FRAGMENT_SOURCE =
109   "varying mediump vec2 vTexCoord;\n"
110   "uniform lowp vec4 uShadowColor;\n"
111   "uniform sampler2D sTexture;\n"
112
113   "void main()\n"
114   "{\n"
115   "  lowp float alpha;\n"
116   "  alpha = texture2D(sTexture, vec2(vTexCoord.x, vTexCoord.y)).a;\n"
117   "  gl_FragColor = vec4(uShadowColor.rgb, uShadowColor.a * alpha);\n"
118   "}\n";
119
120 } // namespace
121
122 ShadowView::ShadowView( float downsampleWidthScale, float downsampleHeightScale )
123 : Control( ControlBehaviour( ACTOR_BEHAVIOUR_NONE ) ),
124   mChildrenRoot(Actor::New()),
125   mCachedShadowColor(DEFAULT_SHADOW_COLOR),
126   mCachedBackgroundColor(DEFAULT_SHADOW_COLOR.r, DEFAULT_SHADOW_COLOR.g, DEFAULT_SHADOW_COLOR.b, 0.0f),
127   mBlurStrengthPropertyIndex(Property::INVALID_INDEX),
128   mShadowColorPropertyIndex(Property::INVALID_INDEX),
129   mDownsampleWidthScale(downsampleWidthScale),
130   mDownsampleHeightScale(downsampleHeightScale)
131 {
132 }
133
134 ShadowView::~ShadowView()
135 {
136 }
137
138 Toolkit::ShadowView ShadowView::New(float downsampleWidthScale, float downsampleHeightScale)
139 {
140   ShadowView* impl = new ShadowView(downsampleWidthScale, downsampleHeightScale);
141
142   Dali::Toolkit::ShadowView handle = Dali::Toolkit::ShadowView( *impl );
143
144   // Second-phase init of the implementation
145   // This can only be done after the CustomActor connection has been made...
146   impl->Initialize();
147
148   return handle;
149 }
150
151 /////////////////////////////////////////////////////////////
152 // for creating a subtree for all user added child actors.
153 // 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.
154 void ShadowView::Add(Actor child)
155 {
156   mChildrenRoot.Add(child);
157 }
158
159 void ShadowView::Remove(Actor child)
160 {
161   mChildrenRoot.Remove(child);
162 }
163
164 void ShadowView::SetShadowPlaneBackground(Actor shadowPlaneBackground)
165 {
166   mShadowPlaneBg = shadowPlaneBackground;
167
168   mShadowPlane = Toolkit::ImageView::New();
169   mShadowPlane.SetName( "SHADOW_PLANE" );
170   mShadowPlane.SetParentOrigin(ParentOrigin::CENTER);
171   mShadowPlane.SetAnchorPoint(AnchorPoint::CENTER);
172
173   mShadowPlane.SetImage(mOutputImage);
174   mShadowPlane.SetProperty( Toolkit::ImageView::Property::IMAGE, mShadowRenderShader );
175   SetShaderConstants();
176
177   // Rather than parent the shadow plane drawable and have constraints to move it to the same
178   // position, instead parent the shadow plane drawable on the shadow plane passed in.
179   mShadowPlaneBg.Add(mShadowPlane);
180   mShadowPlane.SetParentOrigin(ParentOrigin::CENTER);
181   mShadowPlane.SetZ(1.0f);
182
183   ConstrainCamera();
184
185   mShadowPlane.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
186
187   mBlurRootActor.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
188 }
189
190 void ShadowView::SetPointLight(Actor pointLight)
191 {
192   mPointLight = pointLight;
193
194   ConstrainCamera();
195 }
196
197 void ShadowView::SetPointLightFieldOfView(float fieldOfView)
198 {
199   mCameraActor.SetFieldOfView(fieldOfView);
200 }
201
202 void ShadowView::SetShadowColor(Vector4 color)
203 {
204   mCachedShadowColor = color;
205   mCachedBackgroundColor.r = color.r;
206   mCachedBackgroundColor.g = color.g;
207   mCachedBackgroundColor.b = color.b;
208
209   if( mShadowPlane )
210   {
211     mShadowPlane.SetProperty( mShadowColorPropertyIndex, mCachedShadowColor );
212   }
213   if(mRenderSceneTask)
214   {
215     mRenderSceneTask.SetClearColor( mCachedBackgroundColor );
216   }
217 }
218
219 void ShadowView::Activate()
220 {
221   DALI_ASSERT_ALWAYS( Self().OnStage() && "ShadowView should be on stage before calling Activate()\n" );
222
223   // make sure resources are allocated and start the render tasks processing
224   CreateRenderTasks();
225 }
226
227 void ShadowView::Deactivate()
228 {
229   DALI_ASSERT_ALWAYS( Self().OnStage() && "ShadowView should be on stage before calling Deactivate()\n" )
230
231   // stop render tasks processing
232   // Note: render target resources are automatically freed since we set the Image::Unused flag
233   RemoveRenderTasks();
234 }
235
236 ///////////////////////////////////////////////////////////
237 //
238 // Private methods
239 //
240
241 void ShadowView::OnInitialize()
242 {
243   // root actor to parent all user added actors. Used as source actor for shadow render task.
244   mChildrenRoot.SetParentOrigin( ParentOrigin::CENTER );
245   mChildrenRoot.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
246
247   Vector2 stageSize = Stage::GetCurrent().GetSize();
248   mCameraActor = CameraActor::New(stageSize);
249
250   mCameraActor.SetParentOrigin( ParentOrigin::CENTER );
251
252   // Target is constrained to point at the shadow plane origin
253   mCameraActor.SetNearClippingPlane( 1.0f );
254   mCameraActor.SetType( Dali::Camera::FREE_LOOK ); // Camera orientation constrained to point at shadow plane world position
255   mCameraActor.SetOrientation(Radian(Degree(180)), Vector3::YAXIS);
256   mCameraActor.SetPosition(DEFAULT_LIGHT_POSITION);
257
258
259   Property::Map customShader;
260   customShader[ "vertexShader" ] = RENDER_SHADOW_VERTEX_SOURCE;
261   customShader[ "fragmentShader" ] = RENDER_SHADOW_FRAGMENT_SOURCE;
262
263   customShader[ "subdivideGridX" ] = 20;
264   customShader[ "subdivideGridY" ] = 20;
265
266   customShader[ "hints" ] = "outputIsTransparent";
267
268   mShadowRenderShader[ "shader" ] = customShader;
269
270   // Create render targets needed for rendering from light's point of view
271   mSceneFromLightRenderTarget = FrameBufferImage::New( stageSize.width, stageSize.height, Pixel::RGBA8888 );
272
273   mOutputImage = FrameBufferImage::New( stageSize.width * 0.5f, stageSize.height * 0.5f, Pixel::RGBA8888 );
274
275   //////////////////////////////////////////////////////
276   // Connect to actor tree
277
278   Self().Add( mChildrenRoot );
279   Stage::GetCurrent().Add( mCameraActor );
280
281   mBlurFilter.SetRefreshOnDemand(false);
282   mBlurFilter.SetInputImage(mSceneFromLightRenderTarget);
283   mBlurFilter.SetOutputImage(mOutputImage);
284   mBlurFilter.SetSize(stageSize * 0.5f);
285   mBlurFilter.SetPixelFormat(Pixel::RGBA8888);
286
287   mBlurRootActor = Actor::New();
288   mBlurRootActor.SetName( "BLUR_ROOT_ACTOR" );
289
290   // Turn off inheritance to ensure filter renders properly
291   mBlurRootActor.SetParentOrigin( ParentOrigin::CENTER );
292   mBlurRootActor.SetInheritOrientation(false);
293   mBlurRootActor.SetInheritScale(false);
294   mBlurRootActor.SetColorMode(USE_OWN_COLOR);
295
296   Self().Add(mBlurRootActor);
297
298   mBlurFilter.SetRootActor(mBlurRootActor);
299   mBlurFilter.SetBackgroundColor(Vector4::ZERO);
300
301   CustomActor self = Self();
302   // Register a property that the user can use to control the blur in the internal object
303   mBlurStrengthPropertyIndex = self.RegisterProperty(BLUR_STRENGTH_PROPERTY_NAME, BLUR_STRENGTH_DEFAULT);
304
305   Constraint blurStrengthConstraint = Constraint::New<float>( mBlurFilter.GetHandleForAnimateBlurStrength(), mBlurFilter.GetBlurStrengthPropertyIndex(), EqualToConstraint() );
306   blurStrengthConstraint.AddSource( Source( self, mBlurStrengthPropertyIndex) );
307   blurStrengthConstraint.Apply();
308 }
309
310 void ShadowView::OnSizeSet(const Vector3& targetSize)
311 {
312 }
313
314 void ShadowView::ConstrainCamera()
315 {
316   if( mPointLight && mShadowPlane )
317   {
318     // Constrain camera to look directly at center of shadow plane. (mPointLight position
319     // is under control of application, can't use transform inheritance)
320
321     Constraint cameraOrientationConstraint = Constraint::New<Quaternion> ( mCameraActor, Actor::Property::ORIENTATION, &LookAt );
322     cameraOrientationConstraint.AddSource( Source( mShadowPlane, Actor::Property::WORLD_POSITION ) );
323     cameraOrientationConstraint.AddSource( Source( mPointLight,  Actor::Property::WORLD_POSITION ) );
324     cameraOrientationConstraint.AddSource( Source( mShadowPlane, Actor::Property::WORLD_ORIENTATION ) );
325     cameraOrientationConstraint.Apply();
326
327     Constraint pointLightPositionConstraint = Constraint::New<Vector3>( mCameraActor, Actor::Property::POSITION, EqualToConstraint() );
328     pointLightPositionConstraint.AddSource( Source( mPointLight, Actor::Property::WORLD_POSITION ) );
329     pointLightPositionConstraint.Apply();
330   }
331 }
332
333 void ShadowView::CreateRenderTasks()
334 {
335   RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
336
337   // We want the first task to render the scene from the light
338   mRenderSceneTask = taskList.CreateTask();
339
340   mRenderSceneTask.SetCameraActor( mCameraActor );
341   mRenderSceneTask.SetSourceActor( mChildrenRoot );
342   mRenderSceneTask.SetTargetFrameBuffer( mSceneFromLightRenderTarget );
343   mRenderSceneTask.SetInputEnabled( false );
344   mRenderSceneTask.SetClearEnabled( true );
345
346   // background color for render task should be the shadow color, but with alpha 0
347   // we don't want to blend the edges of the content with a BLACK at alpha 0, but
348   // the same shadow color at alpha 0.
349   mRenderSceneTask.SetClearColor( mCachedBackgroundColor );
350
351   mBlurFilter.Enable();
352 }
353
354 void ShadowView::RemoveRenderTasks()
355 {
356   RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
357
358   taskList.RemoveTask(mRenderSceneTask);
359   mRenderSceneTask.Reset();
360
361   mBlurFilter.Disable();
362 }
363
364 void ShadowView::SetShaderConstants()
365 {
366   Property::Index lightCameraProjectionMatrixPropertyIndex = mShadowPlane.RegisterProperty( SHADER_LIGHT_CAMERA_PROJECTION_MATRIX_PROPERTY_NAME, Matrix::IDENTITY );
367   Constraint projectionMatrixConstraint = Constraint::New<Dali::Matrix>( mShadowPlane, lightCameraProjectionMatrixPropertyIndex, EqualToConstraint() );
368   projectionMatrixConstraint.AddSource( Source( mCameraActor, CameraActor::Property::PROJECTION_MATRIX ) );
369   projectionMatrixConstraint.Apply();
370
371   Property::Index lightCameraViewMatrixPropertyIndex = mShadowPlane.RegisterProperty( SHADER_LIGHT_CAMERA_VIEW_MATRIX_PROPERTY_NAME, Matrix::IDENTITY );
372   Constraint viewMatrixConstraint = Constraint::New<Dali::Matrix>( mShadowPlane, lightCameraViewMatrixPropertyIndex, EqualToConstraint() );
373   viewMatrixConstraint.AddSource( Source( mCameraActor, CameraActor::Property::VIEW_MATRIX ) );
374   viewMatrixConstraint.Apply();
375
376   mShadowColorPropertyIndex = mShadowPlane.RegisterProperty( SHADER_SHADOW_COLOR_PROPERTY_NAME, mCachedShadowColor );
377 }
378
379 } // namespace Internal
380
381 } // namespace Toolkit
382
383 } // namespace Dali