2 * Copyright (c) 2021 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"
22 #include <dali/devel-api/common/stage.h>
23 #include <dali/integration-api/debug.h>
24 #include <dali/public-api/animation/constraint.h>
25 #include <dali/public-api/object/type-registry-helper.h>
26 #include <dali/public-api/object/type-registry.h>
27 #include <dali/public-api/render-tasks/render-task-list.h>
28 #include <dali/public-api/rendering/shader.h>
33 #include <dali-toolkit/devel-api/controls/control-devel.h>
34 #include <dali-toolkit/internal/controls/control/control-data-impl.h>
35 #include <dali-toolkit/internal/controls/control/control-renderers.h>
36 #include <dali-toolkit/internal/controls/shadow-view/shadow-view-impl.h>
37 #include <dali-toolkit/internal/filters/blur-two-pass-filter.h>
38 #include <dali-toolkit/internal/graphics/builtin-shader-extern-gen.h>
39 #include <dali-toolkit/public-api/visuals/visual-properties.h>
42 // pixel format / size - set from JSON
43 // aspect ratio property needs to be able to be constrained also for cameras. (now do-able)
44 // default near clip value
46 /////////////////////////////////////////////////////////
47 // IMPLEMENTATION NOTES
49 // As the ShadowView actor changes size, the amount of pixels we need to blur changes. Therefore we need some way of doing this. However:-
50 // OnSetSize() does not get called when ShadowView object size is modified using a Constraint.
51 // 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
52 // OnSizeAnimation() to alter render target sizes.
53 // 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
54 // 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
55 // by using constraints relative to the ShadowView actor size.
69 return Toolkit::ShadowView::New();
72 DALI_TYPE_REGISTRATION_BEGIN(Toolkit::ShadowView, Toolkit::Control, Create)
73 DALI_TYPE_REGISTRATION_END()
75 const float BLUR_STRENGTH_DEFAULT = 1.0f;
77 const Vector3 DEFAULT_LIGHT_POSITION(300.0f, 250.0f, 600.0f);
78 const float DEFAULT_FIELD_OF_VIEW_RADIANS = Math::PI / 4.0f; // 45 degrees
80 const Vector4 DEFAULT_SHADOW_COLOR = Vector4(0.2f, 0.2f, 0.2f, 0.8f);
82 const char* const SHADER_LIGHT_CAMERA_PROJECTION_MATRIX_PROPERTY_NAME = "uLightCameraProjectionMatrix";
83 const char* const SHADER_LIGHT_CAMERA_VIEW_MATRIX_PROPERTY_NAME = "uLightCameraViewMatrix";
84 const char* const SHADER_SHADOW_COLOR_PROPERTY_NAME = "uShadowColor";
85 const char* const BLUR_STRENGTH_PROPERTY_NAME = "BlurStrengthProperty";
86 const char* const SHADOW_COLOR_PROPERTY_NAME = "ShadowColorProperty";
90 ShadowView::ShadowView(float downsampleWidthScale, float downsampleHeightScale)
91 : Control(ControlBehaviour(CONTROL_BEHAVIOUR_DEFAULT)),
92 mChildrenRoot(Actor::New()),
93 mCachedShadowColor(DEFAULT_SHADOW_COLOR),
94 mCachedBackgroundColor(DEFAULT_SHADOW_COLOR.r, DEFAULT_SHADOW_COLOR.g, DEFAULT_SHADOW_COLOR.b, 0.0f),
95 mBlurStrengthPropertyIndex(Property::INVALID_INDEX),
96 mShadowColorPropertyIndex(Property::INVALID_INDEX),
97 mDownsampleWidthScale(downsampleWidthScale),
98 mDownsampleHeightScale(downsampleHeightScale)
102 ShadowView::~ShadowView()
106 Toolkit::ShadowView ShadowView::New(float downsampleWidthScale, float downsampleHeightScale)
108 ShadowView* impl = new ShadowView(downsampleWidthScale, downsampleHeightScale);
110 Dali::Toolkit::ShadowView handle = Dali::Toolkit::ShadowView(*impl);
112 // Second-phase init of the implementation
113 // This can only be done after the CustomActor connection has been made...
119 void ShadowView::SetShadowPlaneBackground(Actor shadowPlaneBackground)
121 mShadowPlaneBg = shadowPlaneBackground;
123 mShadowPlane = Actor::New();
124 mShadowPlane.SetProperty(Actor::Property::NAME, "SHADOW_PLANE");
125 mShadowPlane.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
126 mShadowPlane.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
127 Renderer shadowRenderer = CreateRenderer(SHADER_SHADOW_VIEW_RENDER_SHADER_VERT, SHADER_SHADOW_VIEW_RENDER_SHADER_FRAG, Shader::Hint::OUTPUT_IS_TRANSPARENT, Uint16Pair(20, 20));
128 TextureSet textureSet = shadowRenderer.GetTextures();
129 textureSet.SetTexture(0u, mOutputFrameBuffer.GetColorTexture());
130 mShadowPlane.AddRenderer(shadowRenderer);
132 SetShaderConstants();
134 // Rather than parent the shadow plane drawable and have constraints to move it to the same
135 // position, instead parent the shadow plane drawable on the shadow plane passed in.
136 mShadowPlaneBg.Add(mShadowPlane);
137 mShadowPlane.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
138 mShadowPlane.SetProperty(Actor::Property::POSITION_Z, 1.0f);
142 mShadowPlane.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS);
144 mBlurRootActor.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS);
147 void ShadowView::SetPointLight(Actor pointLight)
149 mPointLight = pointLight;
154 void ShadowView::SetPointLightFieldOfView(float fieldOfView)
156 mCameraActor.SetFieldOfView(fieldOfView);
159 void ShadowView::SetShadowColor(Vector4 color)
161 mCachedShadowColor = color;
162 mCachedBackgroundColor.r = color.r;
163 mCachedBackgroundColor.g = color.g;
164 mCachedBackgroundColor.b = color.b;
168 mShadowPlane.SetProperty(mShadowColorPropertyIndex, mCachedShadowColor);
172 mRenderSceneTask.SetClearColor(mCachedBackgroundColor);
176 void ShadowView::Activate()
178 DALI_ASSERT_ALWAYS(Self().GetProperty<bool>(Actor::Property::CONNECTED_TO_SCENE) && "ShadowView should be on stage before calling Activate()\n");
180 // make sure resources are allocated and start the render tasks processing
184 void ShadowView::Deactivate()
186 DALI_ASSERT_ALWAYS(Self().GetProperty<bool>(Actor::Property::CONNECTED_TO_SCENE) && "ShadowView should be on stage before calling Deactivate()\n")
188 // stop render tasks processing
189 // Note: render target resources are automatically freed since we set the Image::Unused flag
193 ///////////////////////////////////////////////////////////
198 void ShadowView::OnInitialize()
200 // root actor to parent all user added actors. Used as source actor for shadow render task.
201 mChildrenRoot.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
202 mChildrenRoot.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS);
204 Vector2 stageSize = Stage::GetCurrent().GetSize();
205 mCameraActor = CameraActor::New(stageSize);
207 mCameraActor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
209 // Target is constrained to point at the shadow plane origin
210 mCameraActor.SetNearClippingPlane(1.0f);
211 mCameraActor.SetType(Dali::Camera::FREE_LOOK); // Camera orientation constrained to point at shadow plane world position
212 mCameraActor.SetProperty(Actor::Property::ORIENTATION, Quaternion(Radian(Degree(180)), Vector3::YAXIS));
213 mCameraActor.SetProperty(Actor::Property::POSITION, DEFAULT_LIGHT_POSITION);
215 // Create render targets needed for rendering from light's point of view
216 mSceneFromLightRenderTarget = FrameBuffer::New(stageSize.width, stageSize.height, FrameBuffer::Attachment::NONE);
217 Texture textureFromLight = Texture::New(TextureType::TEXTURE_2D, Pixel::RGBA8888, unsigned(stageSize.width), unsigned(stageSize.height));
218 mSceneFromLightRenderTarget.AttachColorTexture(textureFromLight);
220 mOutputFrameBuffer = FrameBuffer::New(stageSize.width * 0.5f, stageSize.height * 0.5f, FrameBuffer::Attachment::NONE);
221 Texture outputTexture = Texture::New(TextureType::TEXTURE_2D, Pixel::RGBA8888, unsigned(stageSize.width * 0.5f), unsigned(stageSize.height * 0.5f));
222 mOutputFrameBuffer.AttachColorTexture(outputTexture);
224 //////////////////////////////////////////////////////
225 // Connect to actor tree
227 Self().Add(mChildrenRoot);
228 Stage::GetCurrent().Add(mCameraActor);
230 mBlurFilter.SetRefreshOnDemand(false);
231 mBlurFilter.SetInputTexture(mSceneFromLightRenderTarget.GetColorTexture());
232 mBlurFilter.SetOutputFrameBuffer(mOutputFrameBuffer);
233 mBlurFilter.SetSize(stageSize * 0.5f);
234 mBlurFilter.SetPixelFormat(Pixel::RGBA8888);
236 mBlurRootActor = Actor::New();
237 mBlurRootActor.SetProperty(Actor::Property::NAME, "BLUR_ROOT_ACTOR");
239 // Turn off inheritance to ensure filter renders properly
240 mBlurRootActor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
241 mBlurRootActor.SetProperty(Actor::Property::INHERIT_POSITION, false);
242 mBlurRootActor.SetProperty(Actor::Property::INHERIT_ORIENTATION, false);
243 mBlurRootActor.SetProperty(Actor::Property::INHERIT_SCALE, false);
244 mBlurRootActor.SetProperty(Actor::Property::COLOR_MODE, USE_OWN_COLOR);
246 Self().Add(mBlurRootActor);
248 mBlurFilter.SetRootActor(mBlurRootActor);
249 mBlurFilter.SetBackgroundColor(Vector4::ZERO);
251 CustomActor self = Self();
252 // Register a property that the user can use to control the blur in the internal object
253 mBlurStrengthPropertyIndex = self.RegisterProperty(BLUR_STRENGTH_PROPERTY_NAME, BLUR_STRENGTH_DEFAULT);
255 Constraint blurStrengthConstraint = Constraint::New<float>(mBlurFilter.GetHandleForAnimateBlurStrength(), mBlurFilter.GetBlurStrengthPropertyIndex(), EqualToConstraint());
256 blurStrengthConstraint.AddSource(Source(self, mBlurStrengthPropertyIndex));
257 blurStrengthConstraint.Apply();
259 Self().SetProperty(DevelControl::Property::ACCESSIBILITY_ROLE, Dali::Accessibility::Role::FILLER);
262 void ShadowView::OnChildAdd(Actor& child)
264 if(child != mChildrenRoot && child != mBlurRootActor)
266 mChildrenRoot.Add(child);
269 Control::OnChildAdd(child);
272 void ShadowView::OnChildRemove(Actor& child)
274 mChildrenRoot.Remove(child);
276 Control::OnChildRemove(child);
279 void ShadowView::ConstrainCamera()
281 if(mPointLight && mShadowPlane)
283 // Constrain camera to look directly at center of shadow plane. (mPointLight position
284 // is under control of application, can't use transform inheritance)
286 Constraint cameraOrientationConstraint = Constraint::New<Quaternion>(mCameraActor, Actor::Property::ORIENTATION, &LookAt);
287 cameraOrientationConstraint.AddSource(Source(mShadowPlane, Actor::Property::WORLD_POSITION));
288 cameraOrientationConstraint.AddSource(Source(mPointLight, Actor::Property::WORLD_POSITION));
289 cameraOrientationConstraint.AddSource(Source(mShadowPlane, Actor::Property::WORLD_ORIENTATION));
290 cameraOrientationConstraint.Apply();
292 Constraint pointLightPositionConstraint = Constraint::New<Vector3>(mCameraActor, Actor::Property::POSITION, EqualToConstraint());
293 pointLightPositionConstraint.AddSource(Source(mPointLight, Actor::Property::WORLD_POSITION));
294 pointLightPositionConstraint.Apply();
298 void ShadowView::CreateRenderTasks()
300 RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
302 // We want the first task to render the scene from the light
303 mRenderSceneTask = taskList.CreateTask();
305 mRenderSceneTask.SetCameraActor(mCameraActor);
306 mRenderSceneTask.SetSourceActor(mChildrenRoot);
307 mRenderSceneTask.SetFrameBuffer(mSceneFromLightRenderTarget);
308 mRenderSceneTask.SetInputEnabled(false);
309 mRenderSceneTask.SetClearEnabled(true);
311 // background color for render task should be the shadow color, but with alpha 0
312 // we don't want to blend the edges of the content with a BLACK at alpha 0, but
313 // the same shadow color at alpha 0.
314 mRenderSceneTask.SetClearColor(mCachedBackgroundColor);
316 mBlurFilter.Enable();
319 void ShadowView::RemoveRenderTasks()
321 RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
323 taskList.RemoveTask(mRenderSceneTask);
324 mRenderSceneTask.Reset();
326 mBlurFilter.Disable();
329 void ShadowView::SetShaderConstants()
331 Property::Index lightCameraProjectionMatrixPropertyIndex = mShadowPlane.RegisterProperty(SHADER_LIGHT_CAMERA_PROJECTION_MATRIX_PROPERTY_NAME, Matrix::IDENTITY);
332 Constraint projectionMatrixConstraint = Constraint::New<Dali::Matrix>(mShadowPlane, lightCameraProjectionMatrixPropertyIndex, EqualToConstraint());
333 projectionMatrixConstraint.AddSource(Source(mCameraActor, CameraActor::Property::PROJECTION_MATRIX));
334 projectionMatrixConstraint.Apply();
336 Property::Index lightCameraViewMatrixPropertyIndex = mShadowPlane.RegisterProperty(SHADER_LIGHT_CAMERA_VIEW_MATRIX_PROPERTY_NAME, Matrix::IDENTITY);
337 Constraint viewMatrixConstraint = Constraint::New<Dali::Matrix>(mShadowPlane, lightCameraViewMatrixPropertyIndex, EqualToConstraint());
338 viewMatrixConstraint.AddSource(Source(mCameraActor, CameraActor::Property::VIEW_MATRIX));
339 viewMatrixConstraint.Apply();
341 mShadowColorPropertyIndex = mShadowPlane.RegisterProperty(SHADER_SHADOW_COLOR_PROPERTY_NAME, mCachedShadowColor);
344 } // namespace Internal
346 } // namespace Toolkit