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