Size negotiation patch 1: Removed SetPreferred size
[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/active-constraint.h>
25 #include <dali/public-api/animation/constraint.h>
26 #include <dali/public-api/common/stage.h>
27 #include <dali/public-api/object/type-registry.h>
28 #include <dali/public-api/object/type-registry-helper.h>
29 #include <dali/public-api/render-tasks/render-task-list.h>
30 #include <dali/integration-api/debug.h>
31
32 // INTERNAL INCLUDES
33 #include <dali-toolkit/internal/controls/shadow-view/shadow-view-impl.h>
34 #include <dali-toolkit/internal/filters/blur-two-pass-filter.h>
35
36 // TODO:
37 // pixel format / size - set from JSON
38 // aspect ratio property needs to be able to be constrained also for cameras. (now do-able)
39 // default near clip value
40 // mChildrenRoot Add()/Remove() overloads - better solution
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   " uniform mediump mat4 uLightCameraProjectionMatrix;\n"
91   " uniform mediump mat4 uLightCameraViewMatrix;\n"
92   "\n"
93   "void main()\n"
94   "{\n"
95     "  gl_Position = uProjection * uModelView * vec4(aPosition,1.0);\n"
96     "  vec4 textureCoords = uLightCameraProjectionMatrix * uLightCameraViewMatrix * uModelMatrix  * vec4(aPosition,1.0);\n"
97     "  vTexCoord = 0.5 + 0.5 * (textureCoords.xy/textureCoords.w);\n"
98   "}\n";
99
100 const char* const RENDER_SHADOW_FRAGMENT_SOURCE =
101   "uniform lowp vec4 uShadowColor;\n"
102   "void main()\n"
103   "{\n"
104   "  lowp float alpha;\n"
105   "  alpha = texture2D(sTexture, vec2(vTexCoord.x, vTexCoord.y)).a;\n"
106   "  gl_FragColor = vec4(uShadowColor.rgb, uShadowColor.a * alpha);\n"
107   "}\n";
108
109 // TODO: Add this to dali-core constraints.h
110 /**
111  * EqualToConstraintMatrix
112  *
113  * f(current, property) = property
114  */
115 struct EqualToConstraintMatrix
116 {
117   EqualToConstraintMatrix(){}
118
119   Dali::Matrix operator()(const Dali::Matrix& current, const PropertyInput& property) {return property.GetMatrix();}
120 };
121
122 } // namespace
123
124 ShadowView::ShadowView( float downsampleWidthScale, float downsampleHeightScale )
125 : Control( CONTROL_BEHAVIOUR_NONE ),
126   mChildrenRoot(Actor::New()),
127   mCachedShadowColor(DEFAULT_SHADOW_COLOR),
128   mCachedBackgroundColor(DEFAULT_SHADOW_COLOR.r, DEFAULT_SHADOW_COLOR.g, DEFAULT_SHADOW_COLOR.b, 0.0f),
129   mBlurStrengthPropertyIndex(Property::INVALID_INDEX),
130   mShadowColorPropertyIndex(Property::INVALID_INDEX),
131   mDownsampleWidthScale(downsampleWidthScale),
132   mDownsampleHeightScale(downsampleHeightScale)
133 {
134 }
135
136 ShadowView::~ShadowView()
137 {
138 }
139
140 Toolkit::ShadowView ShadowView::New(float downsampleWidthScale, float downsampleHeightScale)
141 {
142   ShadowView* impl = new ShadowView(downsampleWidthScale, downsampleHeightScale);
143
144   Dali::Toolkit::ShadowView handle = Dali::Toolkit::ShadowView( *impl );
145
146   // Second-phase init of the implementation
147   // This can only be done after the CustomActor connection has been made...
148   impl->Initialize();
149
150   return handle;
151 }
152
153 /////////////////////////////////////////////////////////////
154 // for creating a subtree for all user added child actors.
155 // 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.
156 void ShadowView::Add(Actor child)
157 {
158   mChildrenRoot.Add(child);
159 }
160
161 void ShadowView::Remove(Actor child)
162 {
163   mChildrenRoot.Remove(child);
164 }
165
166 void ShadowView::SetShadowPlane(Actor shadowPlane)
167 {
168   mShadowPlaneBg = shadowPlane;
169
170   mShadowPlane = ImageActor::New();
171   mShadowPlane.SetName( "SHADOW_PLANE" );
172   mShadowPlane.SetParentOrigin(ParentOrigin::CENTER);
173   mShadowPlane.SetAnchorPoint(AnchorPoint::CENTER);
174
175   mShadowPlane.SetImage(mOutputImage);
176   mShadowPlane.SetShaderEffect(mShadowRenderShader);
177
178   // Rather than parent the shadow plane drawable and have constraints to move it to the same
179   // position, instead parent the shadow plane drawable on the shadow plane passed in.
180   mShadowPlaneBg.Add(mShadowPlane);
181   mShadowPlane.SetParentOrigin(ParentOrigin::CENTER);
182   mShadowPlane.SetZ(1.0f);
183
184   ConstrainCamera();
185
186   mShadowPlane.SetResizePolicy( FILL_TO_PARENT, ALL_DIMENSIONS );
187
188   mBlurRootActor.SetResizePolicy( FILL_TO_PARENT, ALL_DIMENSIONS );
189 }
190
191 void ShadowView::SetPointLight(Actor pointLight)
192 {
193   mPointLight = pointLight;
194
195   ConstrainCamera();
196 }
197
198 void ShadowView::SetPointLightFieldOfView(float fieldOfView)
199 {
200   mCameraActor.SetFieldOfView(fieldOfView);
201 }
202
203 void ShadowView::SetShadowColor(Vector4 color)
204 {
205   mCachedShadowColor = color;
206   mCachedBackgroundColor.r = color.r;
207   mCachedBackgroundColor.g = color.g;
208   mCachedBackgroundColor.b = color.b;
209
210   Self().SetProperty( mShadowColorPropertyIndex, mCachedShadowColor );
211   if(mRenderSceneTask)
212   {
213     mRenderSceneTask.SetClearColor( mCachedBackgroundColor );
214   }
215 }
216
217 void ShadowView::Activate()
218 {
219   DALI_ASSERT_ALWAYS( Self().OnStage() && "ShadowView should be on stage before calling Activate()\n" );
220
221   // make sure resources are allocated and start the render tasks processing
222   CreateRenderTasks();
223 }
224
225 void ShadowView::Deactivate()
226 {
227   DALI_ASSERT_ALWAYS( Self().OnStage() && "ShadowView should be on stage before calling Deactivate()\n" )
228
229   // stop render tasks processing
230   // Note: render target resources are automatically freed since we set the Image::Unused flag
231   RemoveRenderTasks();
232 }
233
234 ///////////////////////////////////////////////////////////
235 //
236 // Private methods
237 //
238
239 void ShadowView::OnInitialize()
240 {
241   // root actor to parent all user added actors. Used as source actor for shadow render task.
242   mChildrenRoot.SetPositionInheritanceMode( Dali::USE_PARENT_POSITION );
243   mChildrenRoot.SetRelayoutEnabled( true );
244   mChildrenRoot.SetResizePolicy( FILL_TO_PARENT, ALL_DIMENSIONS );
245
246   Vector2 stageSize = Stage::GetCurrent().GetSize();
247   mCameraActor = CameraActor::New(stageSize);
248
249   mCameraActor.SetParentOrigin( ParentOrigin::CENTER );
250
251   // Target is constrained to point at the shadow plane origin
252   mCameraActor.SetNearClippingPlane( 1.0f );
253   mCameraActor.SetType( Dali::Camera::FREE_LOOK ); // Camera orientation constrained to point at shadow plane world position
254   mCameraActor.SetOrientation(Radian(Degree(180)), Vector3::YAXIS);
255   mCameraActor.SetPosition(DEFAULT_LIGHT_POSITION);
256
257   mShadowRenderShader = ShaderEffect::New( RENDER_SHADOW_VERTEX_SOURCE, RENDER_SHADOW_FRAGMENT_SOURCE,
258                                            Dali::GeometryType( GEOMETRY_TYPE_IMAGE ),
259                                            ShaderEffect::GeometryHints( ShaderEffect::HINT_GRID | ShaderEffect::HINT_BLENDING ));
260
261   // Create render targets needed for rendering from light's point of view
262   mSceneFromLightRenderTarget = FrameBufferImage::New( stageSize.width, stageSize.height, Pixel::RGBA8888 );
263
264   mOutputImage = FrameBufferImage::New( stageSize.width * 0.5f, stageSize.height * 0.5f, Pixel::RGBA8888 );
265
266   //////////////////////////////////////////////////////
267   // Connect to actor tree
268
269   Self().Add( mChildrenRoot );
270   Stage::GetCurrent().Add( mCameraActor );
271
272   mBlurFilter.SetRefreshOnDemand(false);
273   mBlurFilter.SetInputImage(mSceneFromLightRenderTarget);
274   mBlurFilter.SetOutputImage(mOutputImage);
275   mBlurFilter.SetSize(stageSize * 0.5f);
276   mBlurFilter.SetPixelFormat(Pixel::RGBA8888);
277
278   mBlurRootActor = Actor::New();
279   mBlurRootActor.SetName( "BLUR_ROOT_ACTOR" );
280   mBlurRootActor.SetRelayoutEnabled( true );
281
282   // Turn off inheritance to ensure filter renders properly
283   mBlurRootActor.SetPositionInheritanceMode(USE_PARENT_POSITION);
284   mBlurRootActor.SetInheritOrientation(false);
285   mBlurRootActor.SetInheritScale(false);
286   mBlurRootActor.SetColorMode(USE_OWN_COLOR);
287
288   Self().Add(mBlurRootActor);
289
290   mBlurFilter.SetRootActor(mBlurRootActor);
291   mBlurFilter.SetBackgroundColor(Vector4::ZERO);
292
293   SetShaderConstants();
294 }
295
296 void ShadowView::OnSizeSet(const Vector3& targetSize)
297 {
298 }
299
300 void ShadowView::OnStageConnection()
301 {
302   // TODO: can't call this here, since SetImage() calls fail to connect images to stage, since parent chain not fully on stage yet
303   // 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()
304   //Activate();
305 }
306
307 void ShadowView::OnStageDisconnection()
308 {
309   // TODO: can't call this here, since SetImage() calls fails similarly to above
310   // 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()
311   //Deactivate();
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 =
322       Constraint::New<Quaternion> ( Actor::Property::ORIENTATION,
323                                     Source( mShadowPlane, Actor::Property::WORLD_POSITION ),
324                                     Source( mPointLight,  Actor::Property::WORLD_POSITION ),
325                                     Source( mShadowPlane, Actor::Property::WORLD_ORIENTATION ),
326                                     &LookAt );
327
328     mCameraActor.ApplyConstraint( cameraOrientationConstraint );
329
330     Constraint pointLightPositionConstraint = Constraint::New<Vector3>( Actor::Property::POSITION, Source( mPointLight, Actor::Property::WORLD_POSITION ), EqualToConstraint() );
331
332     mCameraActor.ApplyConstraint( pointLightPositionConstraint );
333   }
334 }
335
336 void ShadowView::CreateRenderTasks()
337 {
338   RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
339
340   // We want the first task to render the scene from the light
341   mRenderSceneTask = taskList.CreateTask();
342
343   mRenderSceneTask.SetCameraActor( mCameraActor );
344   mRenderSceneTask.SetSourceActor( mChildrenRoot );
345   mRenderSceneTask.SetTargetFrameBuffer( mSceneFromLightRenderTarget );
346   mRenderSceneTask.SetInputEnabled( false );
347   mRenderSceneTask.SetClearEnabled( true );
348
349   // background color for render task should be the shadow color, but with alpha 0
350   // we don't want to blend the edges of the content with a BLACK at alpha 0, but
351   // the same shadow color at alpha 0.
352   mRenderSceneTask.SetClearColor( mCachedBackgroundColor );
353
354   mBlurFilter.Enable();
355 }
356
357 void ShadowView::RemoveRenderTasks()
358 {
359   RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
360
361   taskList.RemoveTask(mRenderSceneTask);
362   mRenderSceneTask.Reset();
363
364   mBlurFilter.Disable();
365 }
366
367 void ShadowView::SetShaderConstants()
368 {
369   CustomActor self = Self();
370
371   mShadowRenderShader.SetUniform( SHADER_LIGHT_CAMERA_PROJECTION_MATRIX_PROPERTY_NAME, Matrix::IDENTITY );
372   mShadowRenderShader.SetUniform( SHADER_LIGHT_CAMERA_VIEW_MATRIX_PROPERTY_NAME, Matrix::IDENTITY );
373   mShadowRenderShader.SetUniform( SHADER_SHADOW_COLOR_PROPERTY_NAME, mCachedShadowColor );
374
375   Property::Index lightCameraProjectionMatrixPropertyIndex = mShadowRenderShader.GetPropertyIndex(SHADER_LIGHT_CAMERA_PROJECTION_MATRIX_PROPERTY_NAME);
376   Property::Index lightCameraViewMatrixPropertyIndex = mShadowRenderShader.GetPropertyIndex(SHADER_LIGHT_CAMERA_VIEW_MATRIX_PROPERTY_NAME);
377
378   Constraint projectionMatrixConstraint = Constraint::New<Dali::Matrix>( lightCameraProjectionMatrixPropertyIndex, Source( mCameraActor, CameraActor::Property::PROJECTION_MATRIX ), EqualToConstraintMatrix());
379   Constraint viewMatrixConstraint = Constraint::New<Dali::Matrix>( lightCameraViewMatrixPropertyIndex, Source( mCameraActor, CameraActor::Property::VIEW_MATRIX ), EqualToConstraintMatrix());
380
381   mShadowRenderShader.ApplyConstraint(projectionMatrixConstraint);
382   mShadowRenderShader.ApplyConstraint(viewMatrixConstraint);
383
384   // Register a property that the user can use to control the blur in the internal object
385   mBlurStrengthPropertyIndex = self.RegisterProperty(BLUR_STRENGTH_PROPERTY_NAME, BLUR_STRENGTH_DEFAULT);
386   mBlurFilter.GetHandleForAnimateBlurStrength().ApplyConstraint( Constraint::New<float>( mBlurFilter.GetBlurStrengthPropertyIndex() ,
387                                                                            Source( self, mBlurStrengthPropertyIndex),
388                                                                            EqualToConstraint()) );
389
390   //  Register a property that the user can use to control the color of the shadow.
391   Property::Index index = mShadowRenderShader.GetPropertyIndex(SHADER_SHADOW_COLOR_PROPERTY_NAME);
392   mShadowColorPropertyIndex = self.RegisterProperty(SHADOW_COLOR_PROPERTY_NAME, mCachedShadowColor);
393
394   mShadowRenderShader.ApplyConstraint(Constraint::New<Dali::Vector4>( index, Source( self, mShadowColorPropertyIndex ), EqualToConstraint()) );
395 }
396
397 } // namespace Internal
398
399 } // namespace Toolkit
400
401 } // namespace Dali