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