model3d-view-example.cpp 10 KB
/*
 * Copyright (c) 2020 Samsung Electronics Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

#include <dali-toolkit/dali-toolkit.h>

using namespace Dali;
using Dali::Toolkit::Model3dView;

namespace
{
const int MODEL_NUMBER(3);

const char* const MODEL_FILE[] = {
  DEMO_MODEL_DIR "Dino.obj",
  DEMO_MODEL_DIR "ToyRobot-Metal.obj",
  DEMO_MODEL_DIR "Toyrobot-Plastic.obj"};

const char* const MATERIAL_FILE[] = {
  DEMO_MODEL_DIR "Dino.mtl",
  DEMO_MODEL_DIR "ToyRobot-Metal.mtl",
  DEMO_MODEL_DIR "Toyrobot-Plastic.mtl"};

const char* const IMAGE_PATH(DEMO_IMAGE_DIR "");

const char* BACKGROUND_IMAGE(DEMO_IMAGE_DIR "background-1.jpg");

} // namespace

/*
 * This example shows how to create and display a model3d-view control.
 * The application can cycle between 3 different models, and 3 different shaders.
 * There are two animations running, one is a rotation for the model, one is a light that
 * goes from one side of the model to the other.
 * There are dedicated buttons for changing the models, the shaders and pausing the animations.
 * The animations can also be paused, resumed with the space key
 * A double tap in the model3d-view will make zoom-in/out of the zone clicked
 */

class Model3dViewController : public ConnectionTracker
{
public:
  Model3dViewController(Application& application)
  : mApplication(application),
    mModelCounter(0),
    mModel3dView(),
    mButtonLayer(),
    mTapDetector(),
    mIlluminationShader(Model3dView::DIFFUSE),
    mRotationAnimation(),
    mLightAnimation(),
    mPlaying(false),
    mScaled(false)
  {
    // Connect to the Application's Init signal
    mApplication.InitSignal().Connect(this, &Model3dViewController::Create);
  }

  ~Model3dViewController()
  {
    // Nothing to do here;
  }

  // The Init signal is received once (only) during the Application lifetime
  void Create(Application& application)
  {
    // Get a handle to the window
    Window  window     = application.GetWindow();
    Vector2 screenSize = window.GetSize();

    //Add background
    Toolkit::ImageView backView = Toolkit::ImageView::New(BACKGROUND_IMAGE);
    backView.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
    backView.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
    window.Add(backView);

    mModelCounter = 0;

    mModel3dView = Model3dView::New(MODEL_FILE[0], MATERIAL_FILE[0], IMAGE_PATH);
    mModel3dView.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
    mModel3dView.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
    mModel3dView.SetProperty(Dali::Actor::Property::NAME, "model3dViewControl");
    mModel3dView.SetResizePolicy(ResizePolicy::FIXED, Dimension::ALL_DIMENSIONS);
    mModel3dView.SetProperty(Actor::Property::SIZE, screenSize);

    mModel3dView.SetProperty(Model3dView::Property::LIGHT_POSITION, Vector3(5, 10., 0));

    backView.Add(mModel3dView);

    mIlluminationShader = Model3dView::IlluminationType(mModel3dView.GetProperty<int>(Model3dView::Property::ILLUMINATION_TYPE));

    mButtonLayer = Layer::New();
    mButtonLayer.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS);
    mButtonLayer.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
    mButtonLayer.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
    window.Add(mButtonLayer);

    // Create button for model changing
    Toolkit::PushButton editButton = Toolkit::PushButton::New();
    editButton.SetResizePolicy(ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS);
    editButton.ClickedSignal().Connect(this, &Model3dViewController::OnChangeModelClicked);
    editButton.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
    editButton.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
    editButton.SetProperty(Toolkit::Button::Property::LABEL, "Change Model");
    mButtonLayer.Add(editButton);

    // Create button for shader changing
    editButton = Toolkit::PushButton::New();
    editButton.SetResizePolicy(ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS);
    editButton.ClickedSignal().Connect(this, &Model3dViewController::OnChangeLightingClicked);
    editButton.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_RIGHT);
    editButton.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_RIGHT);
    editButton.SetProperty(Toolkit::Button::Property::LABEL, "Change Shader");
    mButtonLayer.Add(editButton);

    // Create button for pause/resume animation
    editButton = Toolkit::PushButton::New();
    editButton.SetResizePolicy(ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS);
    editButton.ClickedSignal().Connect(this, &Model3dViewController::OnPauseAnimationsClicked);
    editButton.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::BOTTOM_CENTER);
    editButton.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::BOTTOM_CENTER);
    editButton.SetProperty(Toolkit::Button::Property::LABEL, "Pause Animations");
    mButtonLayer.Add(editButton);

    //Create animations
    mLightAnimation = Animation::New(6.f);
    mLightAnimation.AnimateTo(Property(mModel3dView, Model3dView::Property::LIGHT_POSITION), Vector3(-5, 10.0, 0), TimePeriod(0.0f, 3.0f));
    mLightAnimation.AnimateTo(Property(mModel3dView, Model3dView::Property::LIGHT_POSITION), Vector3(5, 10.0, 0), TimePeriod(3.0f, 3.0f));
    mLightAnimation.SetLooping(true);
    mLightAnimation.Play();

    mRotationAnimation = Animation::New(15.f);
    mRotationAnimation.AnimateBy(Property(mModel3dView, Actor::Property::ORIENTATION), Quaternion(Degree(0.f), Degree(360.f), Degree(0.f)));
    mRotationAnimation.SetLooping(true);
    mRotationAnimation.Play();

    mPlaying = true;
    mScaled  = false;

    // Respond to a click anywhere on the window
    window.KeyEventSignal().Connect(this, &Model3dViewController::OnKeyEvent);

    //Create a tap gesture detector for zoom
    mTapDetector = TapGestureDetector::New(2);
    mTapDetector.DetectedSignal().Connect(this, &Model3dViewController::OnTap);

    mTapDetector.Attach(backView);
  }

  /**
   * Main Tap event handler
   */
  void OnTap(Actor actor, const TapGesture& tap)
  {
    if(mScaled)
    {
      mModel3dView.SetProperty(Actor::Property::SCALE, 1.0f);
      mModel3dView.SetProperty(Actor::Property::POSITION, Vector3(0, 0, 0));
      mScaled = false;
    }
    else
    {
      Window  window     = mApplication.GetWindow();
      Vector2 screenSize = window.GetSize();

      const Vector2& screenPoint = tap.GetScreenPoint();
      Vector2        position;
      position.x = screenPoint.x - screenSize.x * 0.5;
      position.y = screenPoint.y - screenSize.y * 0.5;

      float size = 2.5;

      mModel3dView.SetProperty(Actor::Property::SCALE, size);
      mModel3dView.SetProperty(Actor::Property::POSITION, Vector3(-position.x * size, -position.y * size, 0));
      mScaled = true;
    }
  }

  /**
   * Change models button signal function
   */
  bool OnChangeModelClicked(Toolkit::Button button)
  {
    mModelCounter = (mModelCounter + 1) % MODEL_NUMBER;
    mModel3dView.SetProperty(Model3dView::Property::GEOMETRY_URL, MODEL_FILE[mModelCounter]);
    mModel3dView.SetProperty(Model3dView::Property::MATERIAL_URL, MATERIAL_FILE[mModelCounter]);
    return true;
  }

  /**
   * Change shader button signal function
   */
  bool OnChangeLightingClicked(Toolkit::Button button)
  {
    if(mIlluminationShader == Model3dView::DIFFUSE_WITH_NORMAL_MAP)
    {
      mModel3dView.SetProperty(Model3dView::Property::ILLUMINATION_TYPE, Model3dView::DIFFUSE_WITH_TEXTURE);
      mIlluminationShader = Model3dView::IlluminationType(mModel3dView.GetProperty<int>(Model3dView::Property::ILLUMINATION_TYPE));
    }
    else if(mIlluminationShader == Model3dView::DIFFUSE_WITH_TEXTURE)
    {
      mModel3dView.SetProperty(Model3dView::Property::ILLUMINATION_TYPE, Model3dView::DIFFUSE);
      mIlluminationShader = Model3dView::IlluminationType(mModel3dView.GetProperty<int>(Model3dView::Property::ILLUMINATION_TYPE));
    }
    else if(mIlluminationShader == Model3dView::DIFFUSE)
    {
      mModel3dView.SetProperty(Model3dView::Property::ILLUMINATION_TYPE, Model3dView::DIFFUSE_WITH_NORMAL_MAP);
      mIlluminationShader = Model3dView::IlluminationType(mModel3dView.GetProperty<int>(Model3dView::Property::ILLUMINATION_TYPE));
    }

    return true;
  }

  /**
   * Function to pause resume all animations
   */
  void PauseAnimations()
  {
    if(mPlaying)
    {
      mRotationAnimation.Pause();
      mLightAnimation.Pause();

      mPlaying = false;
    }
    else
    {
      mRotationAnimation.Play();
      mLightAnimation.Play();

      mPlaying = true;
    }
  }

  /**
   * Pause button signal function
   */
  bool OnPauseAnimationsClicked(Toolkit::Button button)
  {
    PauseAnimations();

    return true;
  }

  /**
   * Main key event handler
   */
  void OnKeyEvent(const KeyEvent& event)
  {
    if(event.GetState() == KeyEvent::DOWN)
    {
      if(IsKey(event, Dali::DALI_KEY_ESCAPE) || IsKey(event, Dali::DALI_KEY_BACK))
      {
        mApplication.Quit();
      }
      else
      {
        PauseAnimations();
      }
    }
  }

private:
  Application& mApplication;

  int         mModelCounter;
  Model3dView mModel3dView;

  Layer              mButtonLayer;
  TapGestureDetector mTapDetector;

  Model3dView::IlluminationType mIlluminationShader;

  Animation mRotationAnimation;
  Animation mLightAnimation;
  bool      mPlaying;

  bool mScaled;
};

int DALI_EXPORT_API main(int argc, char** argv)
{
  Application           application = Application::New(&argc, &argv);
  Model3dViewController test(application);
  application.MainLoop();
  return 0;
}