2 * Copyright (c) 2017 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include "shadow-view-impl.h"
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>
33 #include <dali-toolkit/public-api/visuals/visual-properties.h>
34 #include <dali-toolkit/internal/controls/control/control-renderers.h>
35 #include <dali-toolkit/internal/controls/shadow-view/shadow-view-impl.h>
36 #include <dali-toolkit/internal/filters/blur-two-pass-filter.h>
39 // pixel format / size - set from JSON
40 // aspect ratio property needs to be able to be constrained also for cameras. (now do-able)
41 // default near clip value
44 /////////////////////////////////////////////////////////
45 // IMPLEMENTATION NOTES
47 // As the ShadowView actor changes size, the amount of pixels we need to blur changes. Therefore we need some way of doing this. However:-
48 // OnSetSize() does not get called when ShadowView object size is modified using a Constraint.
49 // 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
50 // OnSizeAnimation() to alter render target sizes.
51 // 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
52 // 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
53 // by using constraints relative to the ShadowView actor size.
71 return Toolkit::ShadowView::New();
74 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::ShadowView, Toolkit::Control, Create )
75 DALI_TYPE_REGISTRATION_END()
77 const float BLUR_STRENGTH_DEFAULT = 1.0f;
79 const Vector3 DEFAULT_LIGHT_POSITION(300.0f, 250.0f, 600.0f);
80 const float DEFAULT_FIELD_OF_VIEW_RADIANS = Math::PI / 4.0f; // 45 degrees
82 const Vector4 DEFAULT_SHADOW_COLOR = Vector4(0.2f, 0.2f, 0.2f, 0.8f);
84 const char* const SHADER_LIGHT_CAMERA_PROJECTION_MATRIX_PROPERTY_NAME = "uLightCameraProjectionMatrix";
85 const char* const SHADER_LIGHT_CAMERA_VIEW_MATRIX_PROPERTY_NAME = "uLightCameraViewMatrix";
86 const char* const SHADER_SHADOW_COLOR_PROPERTY_NAME = "uShadowColor";
87 const char* const BLUR_STRENGTH_PROPERTY_NAME = "BlurStrengthProperty";
88 const char* const SHADOW_COLOR_PROPERTY_NAME = "ShadowColorProperty";
90 const char* const RENDER_SHADOW_VERTEX_SOURCE =
92 " attribute mediump vec2 aPosition;\n"
93 " uniform mediump mat4 uMvpMatrix;\n"
94 " uniform mediump mat4 uModelMatrix;\n"
95 " uniform vec3 uSize;\n"
96 " varying vec2 vTexCoord;\n"
98 " uniform mediump mat4 uLightCameraProjectionMatrix;\n"
99 " uniform mediump mat4 uLightCameraViewMatrix;\n"
103 " mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);\n"
104 " vertexPosition.xyz *= uSize;\n"
105 " gl_Position = uMvpMatrix * vertexPosition;\n"
106 " vec4 textureCoords = uLightCameraProjectionMatrix * uLightCameraViewMatrix * uModelMatrix * vertexPosition;\n"
107 " vTexCoord = 0.5 + 0.5 * (textureCoords.xy/textureCoords.w);\n"
110 const char* const RENDER_SHADOW_FRAGMENT_SOURCE =
111 "varying mediump vec2 vTexCoord;\n"
112 "uniform lowp vec4 uShadowColor;\n"
113 "uniform sampler2D sTexture;\n"
117 " lowp float alpha;\n"
118 " alpha = texture2D(sTexture, vec2(vTexCoord.x, vTexCoord.y)).a;\n"
119 " gl_FragColor = vec4(uShadowColor.rgb, uShadowColor.a * alpha);\n"
124 ShadowView::ShadowView( float downsampleWidthScale, float downsampleHeightScale )
125 : Control( ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) ),
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)
136 ShadowView::~ShadowView()
140 Toolkit::ShadowView ShadowView::New(float downsampleWidthScale, float downsampleHeightScale)
142 ShadowView* impl = new ShadowView(downsampleWidthScale, downsampleHeightScale);
144 Dali::Toolkit::ShadowView handle = Dali::Toolkit::ShadowView( *impl );
146 // Second-phase init of the implementation
147 // This can only be done after the CustomActor connection has been made...
153 void ShadowView::SetShadowPlaneBackground(Actor shadowPlaneBackground)
155 mShadowPlaneBg = shadowPlaneBackground;
157 mShadowPlane = Actor::New();
158 mShadowPlane.SetProperty( Actor::Property::NAME, "SHADOW_PLANE" );
159 mShadowPlane.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
160 mShadowPlane.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER );
161 Renderer shadowRenderer = CreateRenderer( RENDER_SHADOW_VERTEX_SOURCE, RENDER_SHADOW_FRAGMENT_SOURCE, Shader::Hint::OUTPUT_IS_TRANSPARENT, Uint16Pair(20,20) );
162 TextureSet textureSet = shadowRenderer.GetTextures();
163 textureSet.SetTexture( 0u, mOutputFrameBuffer.GetColorTexture() );
164 mShadowPlane.AddRenderer( shadowRenderer );
166 SetShaderConstants();
168 // Rather than parent the shadow plane drawable and have constraints to move it to the same
169 // position, instead parent the shadow plane drawable on the shadow plane passed in.
170 mShadowPlaneBg.Add( mShadowPlane );
171 mShadowPlane.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
172 mShadowPlane.SetProperty( Actor::Property::POSITION_Z, 1.0f );
176 mShadowPlane.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
178 mBlurRootActor.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
181 void ShadowView::SetPointLight(Actor pointLight)
183 mPointLight = pointLight;
188 void ShadowView::SetPointLightFieldOfView(float fieldOfView)
190 mCameraActor.SetFieldOfView(fieldOfView);
193 void ShadowView::SetShadowColor(Vector4 color)
195 mCachedShadowColor = color;
196 mCachedBackgroundColor.r = color.r;
197 mCachedBackgroundColor.g = color.g;
198 mCachedBackgroundColor.b = color.b;
202 mShadowPlane.SetProperty( mShadowColorPropertyIndex, mCachedShadowColor );
206 mRenderSceneTask.SetClearColor( mCachedBackgroundColor );
210 void ShadowView::Activate()
212 DALI_ASSERT_ALWAYS( Self().OnStage() && "ShadowView should be on stage before calling Activate()\n" );
214 // make sure resources are allocated and start the render tasks processing
218 void ShadowView::Deactivate()
220 DALI_ASSERT_ALWAYS( Self().OnStage() && "ShadowView should be on stage before calling Deactivate()\n" )
222 // stop render tasks processing
223 // Note: render target resources are automatically freed since we set the Image::Unused flag
227 ///////////////////////////////////////////////////////////
232 void ShadowView::OnInitialize()
234 // root actor to parent all user added actors. Used as source actor for shadow render task.
235 mChildrenRoot.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
236 mChildrenRoot.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
238 Vector2 stageSize = Stage::GetCurrent().GetSize();
239 mCameraActor = CameraActor::New(stageSize);
241 mCameraActor.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
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.SetProperty( Actor::Property::ORIENTATION, Quaternion(Radian(Degree(180)), Vector3::YAXIS) );
247 mCameraActor.SetProperty( Actor::Property::POSITION, DEFAULT_LIGHT_POSITION );
249 // Create render targets needed for rendering from light's point of view
250 mSceneFromLightRenderTarget = FrameBuffer::New( stageSize.width, stageSize.height, FrameBuffer::Attachment::NONE );
251 Texture textureFromLight = Texture::New( TextureType::TEXTURE_2D, Pixel::RGBA8888, unsigned(stageSize.width), unsigned(stageSize.height) );
252 mSceneFromLightRenderTarget.AttachColorTexture( textureFromLight );
254 mOutputFrameBuffer = FrameBuffer::New( stageSize.width * 0.5f, stageSize.height * 0.5f, FrameBuffer::Attachment::NONE );
255 Texture outputTexture = Texture::New( TextureType::TEXTURE_2D, Pixel::RGBA8888, unsigned(stageSize.width * 0.5f), unsigned(stageSize.height * 0.5f) );
256 mOutputFrameBuffer.AttachColorTexture( outputTexture );
258 //////////////////////////////////////////////////////
259 // Connect to actor tree
261 Self().Add( mChildrenRoot );
262 Stage::GetCurrent().Add( mCameraActor );
264 mBlurFilter.SetRefreshOnDemand( false );
265 mBlurFilter.SetInputTexture( mSceneFromLightRenderTarget.GetColorTexture() );
266 mBlurFilter.SetOutputFrameBuffer( mOutputFrameBuffer );
267 mBlurFilter.SetSize( stageSize * 0.5f );
268 mBlurFilter.SetPixelFormat( Pixel::RGBA8888 );
270 mBlurRootActor = Actor::New();
271 mBlurRootActor.SetProperty( Actor::Property::NAME, "BLUR_ROOT_ACTOR" );
273 // Turn off inheritance to ensure filter renders properly
274 mBlurRootActor.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
275 mBlurRootActor.SetProperty( Actor::Property::INHERIT_POSITION, false );
276 mBlurRootActor.SetProperty( Actor::Property::INHERIT_ORIENTATION, false );
277 mBlurRootActor.SetProperty( Actor::Property::INHERIT_SCALE, false );
278 mBlurRootActor.SetProperty( Actor::Property::COLOR_MODE, USE_OWN_COLOR );
280 Self().Add( mBlurRootActor );
282 mBlurFilter.SetRootActor(mBlurRootActor);
283 mBlurFilter.SetBackgroundColor(Vector4::ZERO);
285 CustomActor self = Self();
286 // Register a property that the user can use to control the blur in the internal object
287 mBlurStrengthPropertyIndex = self.RegisterProperty(BLUR_STRENGTH_PROPERTY_NAME, BLUR_STRENGTH_DEFAULT);
289 Constraint blurStrengthConstraint = Constraint::New<float>( mBlurFilter.GetHandleForAnimateBlurStrength(), mBlurFilter.GetBlurStrengthPropertyIndex(), EqualToConstraint() );
290 blurStrengthConstraint.AddSource( Source( self, mBlurStrengthPropertyIndex) );
291 blurStrengthConstraint.Apply();
294 void ShadowView::OnChildAdd( Actor& child )
296 if( child != mChildrenRoot && child != mBlurRootActor)
298 mChildrenRoot.Add( child );
301 Control::OnChildAdd( child );
304 void ShadowView::OnChildRemove( Actor& child )
306 mChildrenRoot.Remove( child );
308 Control::OnChildRemove( child );
311 void ShadowView::ConstrainCamera()
313 if( mPointLight && mShadowPlane )
315 // Constrain camera to look directly at center of shadow plane. (mPointLight position
316 // is under control of application, can't use transform inheritance)
318 Constraint cameraOrientationConstraint = Constraint::New<Quaternion> ( mCameraActor, Actor::Property::ORIENTATION, &LookAt );
319 cameraOrientationConstraint.AddSource( Source( mShadowPlane, Actor::Property::WORLD_POSITION ) );
320 cameraOrientationConstraint.AddSource( Source( mPointLight, Actor::Property::WORLD_POSITION ) );
321 cameraOrientationConstraint.AddSource( Source( mShadowPlane, Actor::Property::WORLD_ORIENTATION ) );
322 cameraOrientationConstraint.Apply();
324 Constraint pointLightPositionConstraint = Constraint::New<Vector3>( mCameraActor, Actor::Property::POSITION, EqualToConstraint() );
325 pointLightPositionConstraint.AddSource( Source( mPointLight, Actor::Property::WORLD_POSITION ) );
326 pointLightPositionConstraint.Apply();
330 void ShadowView::CreateRenderTasks()
332 RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
334 // We want the first task to render the scene from the light
335 mRenderSceneTask = taskList.CreateTask();
337 mRenderSceneTask.SetCameraActor( mCameraActor );
338 mRenderSceneTask.SetSourceActor( mChildrenRoot );
339 mRenderSceneTask.SetFrameBuffer( mSceneFromLightRenderTarget );
340 mRenderSceneTask.SetInputEnabled( false );
341 mRenderSceneTask.SetClearEnabled( true );
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 );
348 mBlurFilter.Enable();
351 void ShadowView::RemoveRenderTasks()
353 RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
355 taskList.RemoveTask(mRenderSceneTask);
356 mRenderSceneTask.Reset();
358 mBlurFilter.Disable();
361 void ShadowView::SetShaderConstants()
363 Property::Index lightCameraProjectionMatrixPropertyIndex = mShadowPlane.RegisterProperty( SHADER_LIGHT_CAMERA_PROJECTION_MATRIX_PROPERTY_NAME, Matrix::IDENTITY );
364 Constraint projectionMatrixConstraint = Constraint::New<Dali::Matrix>( mShadowPlane, lightCameraProjectionMatrixPropertyIndex, EqualToConstraint() );
365 projectionMatrixConstraint.AddSource( Source( mCameraActor, CameraActor::Property::PROJECTION_MATRIX ) );
366 projectionMatrixConstraint.Apply();
368 Property::Index lightCameraViewMatrixPropertyIndex = mShadowPlane.RegisterProperty( SHADER_LIGHT_CAMERA_VIEW_MATRIX_PROPERTY_NAME, Matrix::IDENTITY );
369 Constraint viewMatrixConstraint = Constraint::New<Dali::Matrix>( mShadowPlane, lightCameraViewMatrixPropertyIndex, EqualToConstraint() );
370 viewMatrixConstraint.AddSource( Source( mCameraActor, CameraActor::Property::VIEW_MATRIX ) );
371 viewMatrixConstraint.Apply();
373 mShadowColorPropertyIndex = mShadowPlane.RegisterProperty( SHADER_SHADOW_COLOR_PROPERTY_NAME, mCachedShadowColor );
376 } // namespace Internal
378 } // namespace Toolkit