Added shader effect to render quadratic bezier curves and bounded regions on the GPU
[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/common/stage.h>
25 #include <dali/public-api/object/type-registry.h>
26 #include <dali/public-api/render-tasks/render-task-list.h>
27 #include <dali/integration-api/debug.h>
28
29 // INTERNAL INCLUDES
30 #include <dali-toolkit/internal/controls/shadow-view/shadow-view-impl.h>
31 #include <dali-toolkit/internal/filters/blur-two-pass-filter.h>
32
33 // TODO:
34 // pixel format / size - set from JSON
35 // aspect ratio property needs to be able to be constrained also for cameras. (now do-able)
36 // default near clip value
37 // mChildrenRoot Add()/Remove() overloads - better solution
38
39
40 /////////////////////////////////////////////////////////
41 // IMPLEMENTATION NOTES
42
43 // As the ShadowView actor changes size, the amount of pixels we need to blur changes. Therefore we need some way of doing this. However:-
44 // OnSetSize() does not get called when ShadowView object size is modified using a Constraint.
45 // 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
46 // OnSizeAnimation() to alter render target sizes.
47 // 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
48 // 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
49 // by using constraints relative to the ShadowView actor size.
50
51 namespace Dali
52 {
53
54 namespace Toolkit
55 {
56
57 namespace Internal
58 {
59
60 namespace
61 {
62
63 using namespace Dali;
64
65 BaseHandle Create()
66 {
67   return Toolkit::ShadowView::New();
68 }
69
70 TypeRegistration mType( typeid(Toolkit::ShadowView), typeid(Toolkit::Control), Create );
71
72
73 const float BLUR_STRENGTH_DEFAULT = 1.0f;
74
75 const Vector3 DEFAULT_LIGHT_POSITION(300.0f, 250.0f, 600.0f);
76 const float DEFAULT_FIELD_OF_VIEW_RADIANS = Math::PI / 4.0f; // 45 degrees
77
78 const Vector4 DEFAULT_SHADOW_COLOR = Vector4(0.2f, 0.2f, 0.2f, 0.8f);
79
80 const std::string SHADER_LIGHT_CAMERA_PROJECTION_MATRIX_PROPERTY_NAME( "uLightCameraProjectionMatrix" );
81 const std::string SHADER_LIGHT_CAMERA_VIEW_MATRIX_PROPERTY_NAME( "uLightCameraViewMatrix" );
82 const std::string SHADER_SHADOW_COLOR_PROPERTY_NAME( "uShadowColor" );
83
84 const std::string BLUR_STRENGTH_PROPERTY_NAME( "BlurStrengthProperty" );
85 const std::string SHADOW_COLOR_PROPERTY_NAME( "ShadowColorProperty" );
86
87 const char* const RENDER_SHADOW_VERTEX_SOURCE =
88   " uniform mediump mat4 uLightCameraProjectionMatrix;\n"
89   " uniform mediump mat4 uLightCameraViewMatrix;\n"
90   "\n"
91   "void main()\n"
92   "{\n"
93     "  gl_Position = uProjection * uModelView * vec4(aPosition,1.0);\n"
94     "  vec4 textureCoords = uLightCameraProjectionMatrix * uLightCameraViewMatrix * uModelMatrix  * vec4(aPosition,1.0);\n"
95     "  vTexCoord = 0.5 + 0.5 * (textureCoords.xy/textureCoords.w);\n"
96   "}\n";
97
98 const char* const RENDER_SHADOW_FRAGMENT_SOURCE =
99   "uniform lowp vec4 uShadowColor;\n"
100   "void main()\n"
101   "{\n"
102   "  lowp float alpha;\n"
103   "  alpha = texture2D(sTexture, vec2(vTexCoord.x, vTexCoord.y)).a;\n"
104   "  gl_FragColor = vec4(uShadowColor.rgb, uShadowColor.a * alpha);\n"
105   "}\n";
106
107 // TODO: Add this to dali-core constraints.h
108 /**
109  * EqualToConstraintMatrix
110  *
111  * f(current, property) = property
112  */
113 struct EqualToConstraintMatrix
114 {
115   EqualToConstraintMatrix(){}
116
117   Dali::Matrix operator()(const Dali::Matrix& current, const PropertyInput& property) {return property.GetMatrix();}
118 };
119
120 } // namespace
121
122 ShadowView::ShadowView( float downsampleWidthScale, float downsampleHeightScale )
123 : Control( CONTROL_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::SetShadowPlane(Actor shadowPlane)
165 {
166   mShadowPlaneBg = shadowPlane;
167
168   mShadowPlane = ImageActor::New();
169   mShadowPlane.SetParentOrigin(ParentOrigin::CENTER);
170   mShadowPlane.SetAnchorPoint(AnchorPoint::CENTER);
171
172   mShadowPlane.SetImage(mOutputImage);
173   mShadowPlane.SetShaderEffect(mShadowRenderShader);
174
175   // Rather than parent the shadow plane drawable and have constraints to move it to the same
176   // position, instead parent the shadow plane drawable on the shadow plane passed in.
177   mShadowPlaneBg.Add(mShadowPlane);
178   mShadowPlane.SetParentOrigin(ParentOrigin::CENTER);
179   mShadowPlane.SetZ(1.0f);
180
181   ConstrainCamera();
182
183   mShadowPlane.SetSizeMode( SIZE_EQUAL_TO_PARENT );
184
185   mBlurRootActor.SetSizeMode( SIZE_EQUAL_TO_PARENT );
186 }
187
188 void ShadowView::SetPointLight(Actor pointLight)
189 {
190   mPointLight = pointLight;
191
192   ConstrainCamera();
193 }
194
195 void ShadowView::SetPointLightFieldOfView(float fieldOfView)
196 {
197   mCameraActor.SetFieldOfView(fieldOfView);
198 }
199
200 void ShadowView::SetShadowColor(Vector4 color)
201 {
202   mCachedShadowColor = color;
203   mCachedBackgroundColor.r = color.r;
204   mCachedBackgroundColor.g = color.g;
205   mCachedBackgroundColor.b = color.b;
206
207   Self().SetProperty( mShadowColorPropertyIndex, mCachedShadowColor );
208   if(mRenderSceneTask)
209   {
210     mRenderSceneTask.SetClearColor( mCachedBackgroundColor );
211   }
212 }
213
214 void ShadowView::Activate()
215 {
216   DALI_ASSERT_ALWAYS( Self().OnStage() && "ShadowView should be on stage before calling Activate()\n" );
217
218   // make sure resources are allocated and start the render tasks processing
219   CreateRenderTasks();
220 }
221
222 void ShadowView::Deactivate()
223 {
224   DALI_ASSERT_ALWAYS( Self().OnStage() && "ShadowView should be on stage before calling Deactivate()\n" )
225
226   // stop render tasks processing
227   // Note: render target resources are automatically freed since we set the Image::Unused flag
228   RemoveRenderTasks();
229 }
230
231 ///////////////////////////////////////////////////////////
232 //
233 // Private methods
234 //
235
236 void ShadowView::OnInitialize()
237 {
238   // root actor to parent all user added actors. Used as source actor for shadow render task.
239   mChildrenRoot.SetPositionInheritanceMode( Dali::USE_PARENT_POSITION );
240   mChildrenRoot.SetSizeMode( SIZE_EQUAL_TO_PARENT );
241
242   Vector2 stageSize = Stage::GetCurrent().GetSize();
243   mCameraActor = CameraActor::New(stageSize);
244
245   mCameraActor.SetParentOrigin( ParentOrigin::CENTER );
246
247   // Target is constrained to point at the shadow plane origin
248   mCameraActor.SetNearClippingPlane( 1.0f );
249   mCameraActor.SetType( Dali::Camera::FREE_LOOK ); // Camera orientation constrained to point at shadow plane world position
250   mCameraActor.SetRotation(Radian(Degree(180)), Vector3::YAXIS);
251   mCameraActor.SetPosition(DEFAULT_LIGHT_POSITION);
252
253   mShadowRenderShader = ShaderEffect::New( RENDER_SHADOW_VERTEX_SOURCE, RENDER_SHADOW_FRAGMENT_SOURCE,
254                                            Dali::GeometryType( GEOMETRY_TYPE_IMAGE ),
255                                            ShaderEffect::GeometryHints( ShaderEffect::HINT_GRID | ShaderEffect::HINT_BLENDING ));
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
276   // Turn off inheritance to ensure filter renders properly
277   mBlurRootActor.SetPositionInheritanceMode(USE_PARENT_POSITION);
278   mBlurRootActor.SetInheritRotation(false);
279   mBlurRootActor.SetInheritScale(false);
280   mBlurRootActor.SetColorMode(USE_OWN_COLOR);
281
282   Self().Add(mBlurRootActor);
283
284   mBlurFilter.SetRootActor(mBlurRootActor);
285   mBlurFilter.SetBackgroundColor(Vector4::ZERO);
286
287   SetShaderConstants();
288 }
289
290 void ShadowView::OnSizeSet(const Vector3& targetSize)
291 {
292 }
293
294 void ShadowView::OnStageConnection()
295 {
296   // TODO: can't call this here, since SetImage() calls fail to connect images to stage, since parent chain not fully on stage yet
297   // 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()
298   //Activate();
299 }
300
301 void ShadowView::OnStageDisconnection()
302 {
303   // TODO: can't call this here, since SetImage() calls fails similarly to above
304   // 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()
305   //Deactivate();
306 }
307
308 void ShadowView::ConstrainCamera()
309 {
310   if( mPointLight && mShadowPlane )
311   {
312     // Constrain camera to look directly at center of shadow plane. (mPointLight position
313     // is under control of application, can't use transform inheritance)
314
315     Constraint cameraOrientationConstraint =
316       Constraint::New<Quaternion> ( Actor::ROTATION,
317                                     Source( mShadowPlane, Actor::WORLD_POSITION ),
318                                     Source( mPointLight,  Actor::WORLD_POSITION ),
319                                     Source( mShadowPlane, Actor::WORLD_ROTATION ),
320                                     &LookAt );
321
322     mCameraActor.ApplyConstraint( cameraOrientationConstraint );
323
324     Constraint pointLightPositionConstraint = Constraint::New<Vector3>( Actor::POSITION, Source( mPointLight, Actor::WORLD_POSITION ), EqualToConstraint() );
325
326     mCameraActor.ApplyConstraint( pointLightPositionConstraint );
327   }
328 }
329
330 void ShadowView::CreateRenderTasks()
331 {
332   RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
333
334   // We want the first task to render the scene from the light
335   mRenderSceneTask = taskList.CreateTask();
336
337   mRenderSceneTask.SetCameraActor( mCameraActor );
338   mRenderSceneTask.SetSourceActor( mChildrenRoot );
339   mRenderSceneTask.SetTargetFrameBuffer( mSceneFromLightRenderTarget );
340   mRenderSceneTask.SetInputEnabled( false );
341   mRenderSceneTask.SetClearEnabled( true );
342
343   // background color for render task should be the shadow color, but with alpha 0
344   // we don't want to blend the edges of the content with a BLACK at alpha 0, but
345   // the same shadow color at alpha 0.
346   mRenderSceneTask.SetClearColor( mCachedBackgroundColor );
347
348   mBlurFilter.Enable();
349 }
350
351 void ShadowView::RemoveRenderTasks()
352 {
353   RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
354
355   taskList.RemoveTask(mRenderSceneTask);
356   mRenderSceneTask.Reset();
357
358   mBlurFilter.Disable();
359 }
360
361 void ShadowView::SetShaderConstants()
362 {
363   CustomActor self = Self();
364
365   mShadowRenderShader.SetUniform( SHADER_LIGHT_CAMERA_PROJECTION_MATRIX_PROPERTY_NAME, Matrix::IDENTITY );
366   mShadowRenderShader.SetUniform( SHADER_LIGHT_CAMERA_VIEW_MATRIX_PROPERTY_NAME, Matrix::IDENTITY );
367   mShadowRenderShader.SetUniform( SHADER_SHADOW_COLOR_PROPERTY_NAME, mCachedShadowColor );
368
369   Property::Index lightCameraProjectionMatrixPropertyIndex = mShadowRenderShader.GetPropertyIndex(SHADER_LIGHT_CAMERA_PROJECTION_MATRIX_PROPERTY_NAME);
370   Property::Index lightCameraViewMatrixPropertyIndex = mShadowRenderShader.GetPropertyIndex(SHADER_LIGHT_CAMERA_VIEW_MATRIX_PROPERTY_NAME);
371
372   Constraint projectionMatrixConstraint = Constraint::New<Dali::Matrix>( lightCameraProjectionMatrixPropertyIndex, Source( mCameraActor, CameraActor::PROJECTION_MATRIX ), EqualToConstraintMatrix());
373   Constraint viewMatrixConstraint = Constraint::New<Dali::Matrix>( lightCameraViewMatrixPropertyIndex, Source( mCameraActor, CameraActor::VIEW_MATRIX ), EqualToConstraintMatrix());
374
375   mShadowRenderShader.ApplyConstraint(projectionMatrixConstraint);
376   mShadowRenderShader.ApplyConstraint(viewMatrixConstraint);
377
378   // Register a property that the user can use to control the blur in the internal object
379   mBlurStrengthPropertyIndex = self.RegisterProperty(BLUR_STRENGTH_PROPERTY_NAME, BLUR_STRENGTH_DEFAULT);
380   mBlurFilter.GetHandleForAnimateBlurStrength().ApplyConstraint( Constraint::New<float>( mBlurFilter.GetBlurStrengthPropertyIndex() ,
381                                                                            Source( self, mBlurStrengthPropertyIndex),
382                                                                            EqualToConstraint()) );
383
384   //  Register a property that the user can use to control the color of the shadow.
385   Property::Index index = mShadowRenderShader.GetPropertyIndex(SHADER_SHADOW_COLOR_PROPERTY_NAME);
386   mShadowColorPropertyIndex = self.RegisterProperty(SHADOW_COLOR_PROPERTY_NAME, mCachedShadowColor);
387
388   mShadowRenderShader.ApplyConstraint(Constraint::New<Dali::Vector4>( index, Source( self, mShadowColorPropertyIndex ), EqualToConstraint()) );
389 }
390
391 } // namespace Internal
392
393 } // namespace Toolkit
394
395 } // namespace Dali