2 * Copyright (c) 2020 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 "shared/view.h"
21 #include <dali-toolkit/dali-toolkit.h>
22 #include <dali-toolkit/devel-api/controls/shadow-view/shadow-view.h>
23 #include <dali/dali.h>
28 using namespace Dali::Toolkit;
30 using namespace DemoHelper;
34 const char* BACKGROUND_IMAGE(DEMO_IMAGE_DIR "background-default.png");
35 const char* TOOLBAR_IMAGE(DEMO_IMAGE_DIR "top-bar.png");
37 const char* APPLICATION_TITLE_PAN_LIGHT("Lighting: Pan Light");
38 const char* APPLICATION_TITLE_ROTATE_OBJECT("Lighting: Rotate Object");
39 const char* APPLICATION_TITLE_PAN_SCENE("Lighting: Pan Scene");
40 const char* APPLICATION_TITLE_ROTATE_SCENE("Lighting: Rotate Scene");
41 const char* CHANGE_EFFECT_IMAGE(DEMO_IMAGE_DIR "icon-change.png");
42 const char* CHANGE_EFFECT_IMAGE_SELECTED(DEMO_IMAGE_DIR "icon-change-selected.png");
43 const char* RESET_ICON(DEMO_IMAGE_DIR "icon-reset.png");
44 const char* RESET_ICON_SELECTED(DEMO_IMAGE_DIR "icon-reset-selected.png");
46 const char* SCENE_IMAGE_1(DEMO_IMAGE_DIR "gallery-small-10.jpg");
47 const char* SCENE_IMAGE_2(DEMO_IMAGE_DIR "gallery-small-42.jpg");
48 const char* SCENE_IMAGE_3(DEMO_IMAGE_DIR "gallery-small-48.jpg");
50 const float MIN_PINCH_SCALE(0.3f);
51 const float MAX_PINCH_SCALE(2.05f);
53 const float R3_2(0.8660254);
54 const Vector3 TOP_POINT(0.0f, -1.0f, 0.0f);
55 const Vector3 LEFT_POINT(-R3_2, 0.5f, 0.0f);
56 const Vector3 RIGHT_POINT(R3_2, 0.5f, 0.0f);
57 const Vector3 FRONT_POINT(0.0f, 0.0f, 20.0f);
59 const Vector2 DEFAULT_WINDOW_SIZE(480.0f, 800.0f);
61 const float X_ROTATION_DISPLACEMENT_FACTOR = 60.f;
62 const float Y_ROTATION_DISPLACEMENT_FACTOR = 60.f;
63 const float LIGHT_PAN_X_DISPLACEMENT_FACTOR = 1 / 360.f;
64 const float LIGHT_PAN_Y_DISPLACEMENT_FACTOR = 1 / 360.f;
69 * This example shows a fixed point light onto an animating set of images
70 * casting a shadow onto a wall. The whole scene can be rotated.
73 class TestApp : public ConnectionTracker
78 * @param application class, stored as reference
80 TestApp(Application& app)
96 mPanGestureDetector(),
97 mPinchGestureDetector(),
98 mTapGestureDetector(),
99 mTranslation(22.0f, -1.0f, 0.0f),
100 mSceneXRotation(Degree(-6.0f)), // Initial values give a reasonable off-straight view.
101 mSceneYRotation(Degree(20.0f)),
102 mLightXRotation(Degree(-1.5f)),
103 mLightYRotation(Degree(-9.5f)),
104 mObjectXRotation(0.0f),
105 mObjectYRotation(0.0f),
107 mScaleAtPinchStart(0.6f),
108 mAngle1Index(Property::INVALID_INDEX),
109 mAngle3Index(Property::INVALID_INDEX),
113 app.InitSignal().Connect(this, &TestApp::Create);
114 app.TerminateSignal().Connect(this, &TestApp::Terminate);
119 // Nothing to do here; All the members of this class get deleted automatically and they delete their children
123 struct RotationConstraint
125 RotationConstraint(float sign)
130 void operator()(Quaternion& current, const PropertyInputContainer& inputs)
132 Radian angle(inputs[0]->GetFloat());
133 current = Quaternion(angle * mSign, Vector3::YAXIS);
140 * This method gets called once the main loop of application is up and running
142 void Create(Application& app)
144 srand(0); // Want repeatable path
146 app.GetWindow().KeyEventSignal().Connect(this, &TestApp::OnKeyEvent);
148 CreateToolbarAndView(app);
149 CreateShadowViewAndLights();
153 void CreateToolbarAndView(Application& app)
155 // Creates a default view with a default tool bar.
156 // The view is added to the window.
157 Toolkit::ToolBar toolBar;
158 mContents = DemoHelper::CreateView(app,
165 // Add an effect-changing button on the right of the tool bar.
166 Toolkit::PushButton effectChangeButton = Toolkit::PushButton::New();
167 effectChangeButton.SetProperty(Toolkit::Button::Property::UNSELECTED_BACKGROUND_VISUAL, CHANGE_EFFECT_IMAGE);
168 effectChangeButton.SetProperty(Toolkit::Button::Property::SELECTED_BACKGROUND_VISUAL, CHANGE_EFFECT_IMAGE_SELECTED);
169 effectChangeButton.ClickedSignal().Connect(this, &TestApp::OnEffectButtonClicked);
170 toolBar.AddControl(effectChangeButton, DemoHelper::DEFAULT_VIEW_STYLE.mToolBarButtonPercentage, Toolkit::Alignment::HORIZONTAL_RIGHT, DemoHelper::DEFAULT_MODE_SWITCH_PADDING);
172 // Add title to the tool bar.
173 mTitleActor = DemoHelper::CreateToolBarLabel("");
174 toolBar.AddControl(mTitleActor, DemoHelper::DEFAULT_VIEW_STYLE.mToolBarTitlePercentage, Toolkit::Alignment::HORIZONTAL_CENTER);
177 mTitleActor.SetProperty(TextLabel::Property::TEXT, std::string(APPLICATION_TITLE_PAN_LIGHT));
180 Toolkit::PushButton resetButton = Toolkit::PushButton::New();
181 resetButton.SetProperty(Toolkit::Button::Property::UNSELECTED_BACKGROUND_VISUAL, RESET_ICON);
182 resetButton.SetProperty(Toolkit::Button::Property::SELECTED_BACKGROUND_VISUAL, RESET_ICON_SELECTED);
183 resetButton.ClickedSignal().Connect(this, &TestApp::OnResetPressed);
184 toolBar.AddControl(resetButton, DemoHelper::DEFAULT_VIEW_STYLE.mToolBarButtonPercentage, Toolkit::Alignment::HORIZONTAL_CENTER, DemoHelper::DEFAULT_PLAY_PADDING);
187 mView.SetProperty(Actor::Property::POSITION, Vector3(0.0f, 0.0f, 0.0f));
189 mContents.SetProperty(Layer::Property::BEHAVIOR, Layer::LAYER_3D);
190 mContents.SetProperty(Actor::Property::POSITION, mTranslation);
191 mContents.SetProperty(Actor::Property::ORIENTATION, CalculateWorldRotation(mSceneXRotation, mSceneYRotation));
192 mContents.SetProperty(Actor::Property::SCALE, Vector3(mPinchScale, mPinchScale, mPinchScale));
194 mPanGestureDetector = PanGestureDetector::New();
195 mPanGestureDetector.Attach(mView);
196 mPanGestureDetector.DetectedSignal().Connect(this, &TestApp::OnPan);
198 mPinchGestureDetector = PinchGestureDetector::New();
199 mPinchGestureDetector.Attach(mView);
200 mPinchGestureDetector.DetectedSignal().Connect(this, &TestApp::OnPinch);
202 mTapGestureDetector = TapGestureDetector::New();
203 mTapGestureDetector.Attach(mView);
204 mTapGestureDetector.DetectedSignal().Connect(this, &TestApp::OnTap);
207 void CreateShadowViewAndLights()
209 mShadowView = Toolkit::ShadowView::New();
210 mShadowView.SetProperty(Dali::Actor::Property::NAME, "Container");
211 mShadowView.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
212 mShadowView.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
213 mShadowView.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS);
214 mShadowView.SetPointLightFieldOfView(Math::PI / 2.0f);
215 mContents.Add(mShadowView);
217 mShadowPlaneBg = ImageView::New(DEMO_IMAGE_DIR "brick-wall.jpg");
218 mShadowPlaneBg.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
219 mShadowPlaneBg.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
220 mShadowPlaneBg.SetProperty(Dali::Actor::Property::NAME, "Plane");
221 mShadowPlaneBg.SetProperty(Actor::Property::SIZE, Vector2(1000.0f, 1000.0f));
222 mContents.Add(mShadowPlaneBg);
223 mShadowPlaneBg.SetProperty(Actor::Property::POSITION, Vector3(50.0f, 50.0f, -200.0f));
225 mShadowView.SetShadowPlaneBackground(mShadowPlaneBg);
226 mShadowView.Activate();
228 mLightAnchor = Actor::New();
229 mLightAnchor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
230 mLightAnchor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
231 mLightAnchor.SetProperty(Actor::Property::ORIENTATION, CalculateWorldRotation(mLightXRotation, mLightYRotation));
233 // Work out a scaling factor as the initial light position was calculated for desktop
234 // Need to scale light position as scene actor size is based on window size (i.e. much bigger on device)
235 Vector2 windowSize(mApp.GetWindow().GetSize());
236 float scaleFactor = windowSize.x / DEFAULT_WINDOW_SIZE.x;
238 mCastingLight = Actor::New();
239 mCastingLight.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
240 mCastingLight.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
241 mCastingLight.SetProperty(Actor::Property::POSITION, Vector3(0.0f, 0.0f, 800.0f) * scaleFactor);
243 TextLabel text = TextLabel::New("Light");
244 text.SetProperty(TextLabel::Property::POINT_SIZE, 20.0f);
245 text.SetResizePolicy(ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS);
246 text.SetProperty(Actor::Property::COLOR, Color::BLUE);
248 mCastingLight.Add(text);
249 mLightAnchor.Add(mCastingLight);
250 mShadowPlaneBg.Add(mLightAnchor);
252 text.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
253 mShadowView.SetPointLight(mCastingLight);
258 mSceneActor = Actor::New();
259 mSceneActor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
261 // Create and add images to the scene actor:
262 mImageActor1 = ImageView::New(SCENE_IMAGE_1);
263 mImageActor2 = ImageView::New(SCENE_IMAGE_2);
264 mImageActor3 = ImageView::New(SCENE_IMAGE_3);
266 mImageActor1.SetResizePolicy(ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS);
267 mImageActor2.SetResizePolicy(ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS);
268 mImageActor3.SetResizePolicy(ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS);
270 mImageActor2.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
272 mImageActor1.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER_LEFT);
273 mImageActor1.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER_RIGHT);
275 mImageActor3.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER_RIGHT);
276 mImageActor3.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER_LEFT);
278 mSceneActor.Add(mImageActor2);
279 mImageActor2.Add(mImageActor1);
280 mImageActor2.Add(mImageActor3);
282 Property::Index angleIndex = mImageActor2.RegisterProperty("angle", Property::Value(Dali::ANGLE_30));
283 Source angleSrc(mImageActor2, angleIndex);
285 Constraint constraint = Constraint::New<Quaternion>(mImageActor1, Actor::Property::ORIENTATION, RotationConstraint(-1.0f));
286 constraint.AddSource(angleSrc);
289 constraint = Constraint::New<Quaternion>(mImageActor3, Actor::Property::ORIENTATION, RotationConstraint(+1.0f));
290 constraint.AddSource(angleSrc);
293 mSceneAnimation = Animation::New(2.5f);
295 // Want to animate angle from 30 => -30 and back again smoothly.
297 mSceneAnimation.AnimateTo(Property(mImageActor2, angleIndex), Property::Value(-Dali::ANGLE_30), AlphaFunction::SIN);
299 mSceneAnimation.SetLooping(true);
300 mSceneAnimation.Play();
302 mSceneActor.SetProperty(Actor::Property::SIZE, Vector2(250.0f, 250.0f));
303 mSceneActor.SetProperty(Actor::Property::POSITION, Vector3(0.0f, 0.0f, 130.0f));
304 mShadowView.Add(mSceneActor);
307 Quaternion CalculateWorldRotation(Radian XRotation, Radian YRotation)
309 Quaternion p(XRotation, Vector3::XAXIS);
310 Quaternion q(YRotation, Vector3::YAXIS);
314 void OnTap(Dali::Actor actor, const TapGesture& gesture)
320 mSceneAnimation.Pause();
325 mSceneAnimation.Play();
331 void OnPan(Actor actor, const PanGesture& gesture)
333 switch(gesture.GetState())
335 case GestureState::CONTINUING:
337 const Vector2& displacement = gesture.GetDisplacement();
342 mLightXRotation = mLightXRotation - displacement.y * LIGHT_PAN_X_DISPLACEMENT_FACTOR; // X displacement rotates around Y axis
343 mLightXRotation = Clamp(mLightXRotation, -Dali::ANGLE_45, Dali::ANGLE_45);
344 mLightYRotation = mLightYRotation + displacement.x * LIGHT_PAN_Y_DISPLACEMENT_FACTOR; // Y displacement rotates around X axis
345 mLightYRotation = Clamp(mLightYRotation, -Dali::ANGLE_45, Dali::ANGLE_45);
346 mLightAnchor.SetProperty(Actor::Property::ORIENTATION, CalculateWorldRotation(mLightXRotation, mLightYRotation));
352 mTranslation += Vector3(displacement.x, displacement.y, 0.f);
353 mContents.SetProperty(Actor::Property::POSITION, mTranslation);
359 mSceneXRotation = mSceneXRotation - displacement.y / X_ROTATION_DISPLACEMENT_FACTOR; // X displacement rotates around Y axis
360 mSceneXRotation = Clamp(mSceneXRotation, -Dali::ANGLE_90, Dali::ANGLE_90);
361 mSceneYRotation = mSceneYRotation + displacement.x / Y_ROTATION_DISPLACEMENT_FACTOR; // Y displacement rotates around X axis
362 mSceneYRotation = Clamp(mSceneYRotation, -Dali::ANGLE_90, Dali::ANGLE_90);
363 mContents.SetProperty(Actor::Property::ORIENTATION, CalculateWorldRotation(mSceneXRotation, mSceneYRotation));
369 mObjectXRotation = mObjectXRotation - displacement.y / X_ROTATION_DISPLACEMENT_FACTOR; // X displacement rotates around Y axis
370 mObjectYRotation = mObjectYRotation + displacement.x / Y_ROTATION_DISPLACEMENT_FACTOR; // Y displacement rotates around X axis
371 mSceneActor.SetProperty(Actor::Property::ORIENTATION, CalculateWorldRotation(mObjectXRotation, mObjectYRotation));
378 case GestureState::FINISHED:
379 // Start animation at last known speed
387 void OnPinch(Actor actor, const PinchGesture& gesture)
389 if(gesture.GetState() == GestureState::STARTED)
391 mScaleAtPinchStart = mContents.GetCurrentProperty<Vector3>(Actor::Property::SCALE).x;
393 mPinchScale = Clamp(mScaleAtPinchStart * gesture.GetScale(), MIN_PINCH_SCALE, MAX_PINCH_SCALE);
395 mContents.SetProperty(Actor::Property::SCALE, Vector3(mPinchScale, mPinchScale, mPinchScale));
398 void Terminate(Application& app)
402 mApp.GetWindow().Remove(mSceneActor);
406 mApp.GetWindow().Remove(mView);
410 void OnKeyEvent(const KeyEvent& event)
412 if(event.GetState() == KeyEvent::DOWN)
414 if(IsKey(event, Dali::DALI_KEY_ESCAPE) || IsKey(event, Dali::DALI_KEY_BACK))
421 bool OnEffectButtonClicked(Toolkit::Button button)
426 mPanState = ROTATE_OBJECT;
427 mTitleActor.SetProperty(TextLabel::Property::TEXT, std::string(APPLICATION_TITLE_ROTATE_OBJECT));
430 mPanState = ROTATE_SCENE;
431 mTitleActor.SetProperty(TextLabel::Property::TEXT, std::string(APPLICATION_TITLE_ROTATE_SCENE));
434 mPanState = PAN_SCENE;
435 mTitleActor.SetProperty(TextLabel::Property::TEXT, std::string(APPLICATION_TITLE_PAN_SCENE));
438 mPanState = PAN_LIGHT;
439 mTitleActor.SetProperty(TextLabel::Property::TEXT, std::string(APPLICATION_TITLE_PAN_LIGHT));
448 bool OnResetPressed(Toolkit::Button button)
451 mTranslation = Vector3::ZERO;
452 mContents.SetProperty(Actor::Property::POSITION, mTranslation);
454 // Align scene so that light anchor orientation is Z Axis
455 mSceneXRotation = -mLightXRotation;
456 mSceneYRotation = -mLightYRotation;
457 mContents.SetProperty(Actor::Property::ORIENTATION, CalculateWorldRotation(mSceneXRotation, mSceneYRotation));
464 Toolkit::Control mView;
467 Animation mAnimation;
468 Animation mSceneAnimation;
470 Toolkit::ShadowView mShadowView;
471 ImageView mShadowPlaneBg;
472 ImageView mShadowPlane;
475 ImageView mImageActor1;
476 ImageView mImageActor2;
477 ImageView mImageActor3;
478 PanGestureDetector mPanGestureDetector;
479 PinchGestureDetector mPinchGestureDetector;
480 TapGestureDetector mTapGestureDetector;
481 Vector3 mTranslation;
482 Radian mSceneXRotation;
483 Radian mSceneYRotation;
484 Radian mLightXRotation;
485 Radian mLightYRotation;
486 Radian mObjectXRotation;
487 Radian mObjectYRotation;
489 float mScaleAtPinchStart;
491 Property::Index mAngle1Index;
492 Property::Index mAngle3Index;
494 Toolkit::TextLabel mTitleActor;
507 /*****************************************************************************/
509 int DALI_EXPORT_API main(int argc, char** argv)
511 Application app = Application::New(&argc, &argv, DEMO_THEME_PATH);