Update to Cubism SDK 4-r.2. Incompatible scaling changes.
[mouse-tracker-for-cubism.git] / example / demo.patch
index c6b78d0..637b3ab 100644 (file)
@@ -1,12 +1,12 @@
 diff -pruN --exclude build ./demo_clean/CMakeLists.txt ./demo_dev/CMakeLists.txt
---- ./demo_clean/CMakeLists.txt        2020-09-27 17:43:12.069477246 +0100
-+++ ./demo_dev/CMakeLists.txt  2020-07-11 22:52:49.099117981 +0100
+--- ./demo_clean/CMakeLists.txt        2021-02-17 01:23:17.000000000 +0000
++++ ./demo_dev/CMakeLists.txt  2021-04-28 12:32:48.468744883 +0100
 @@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.16)
  # Set app name.
  set(APP_NAME Demo)
  # Set directory paths.
 -set(SDK_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../../../..)
-+set(SDK_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../CubismSdkForNative-4-r.1)
++set(SDK_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../CubismSdkForNative-4-r.2)
  set(CORE_PATH ${SDK_ROOT_PATH}/Core)
  set(FRAMEWORK_PATH ${SDK_ROOT_PATH}/Framework)
  set(THIRD_PARTY_PATH ${SDK_ROOT_PATH}/Samples/OpenGL/thirdParty)
@@ -19,72 +19,88 @@ diff -pruN --exclude build ./demo_clean/CMakeLists.txt ./demo_dev/CMakeLists.txt
  set(CMAKE_CXX_STANDARD_REQUIRED ON)
  set(CMAKE_CXX_EXTENSIONS OFF)
  
-@@ -64,6 +64,9 @@ target_link_libraries(Framework Live2DCu
+@@ -64,6 +64,11 @@ target_link_libraries(Framework Live2DCu
  # Find opengl libraries.
  find_package(OpenGL REQUIRED)
  
-+# Add FacialLandmarksForCubism
-+add_subdirectory(../.. FacialLandmarksForCubism_build)
++# Add MouseTrackerForCubism
++find_package(PkgConfig)
++pkg_check_modules(GTKMM gtkmm-3.0)
++add_subdirectory(../.. MouseTrackerForCubism_build)
 +
  # Make executable app.
  add_executable(${APP_NAME})
  # Add source files.
-@@ -73,9 +76,11 @@ target_link_libraries(${APP_NAME}
+@@ -73,9 +78,20 @@ target_link_libraries(${APP_NAME}
    Framework
    glfw
    ${OPENGL_LIBRARIES}
-+  FacialLandmarksForCubism
++  MouseTrackerForCubism
 +  stdc++fs
  )
  # Specify include directories.
 -target_include_directories(${APP_NAME} PRIVATE ${STB_PATH})
-+target_include_directories(${APP_NAME} PRIVATE ${STB_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/../../include)
- # Copy resource directory to build directory.
- add_custom_command(
-@@ -86,6 +91,17 @@ add_custom_command(
-       copy_directory ${RES_PATH} $<TARGET_FILE_DIR:${APP_NAME}>/Resources
- )
-+# Copy shape predictor trained dataset to build directory
-+set(DLIB_SHAPE_PREDICTOR_DATA ${CMAKE_CURRENT_SOURCE_DIR}/../shape_predictor_68_face_landmarks.dat
-+    CACHE FILEPATH "Path to dlib shape predictor trained dataset")
++target_include_directories(${APP_NAME} PRIVATE ${STB_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/../../include ${GTKMM_INCLUDE_DIRS})
++
++# Copy GUI to build directory
 +add_custom_command(
 +  TARGET ${APP_NAME}
 +  POST_BUILD
 +  COMMAND
 +    ${CMAKE_COMMAND} -E
-+      copy ${DLIB_SHAPE_PREDICTOR_DATA} $<TARGET_FILE_DIR:${APP_NAME}>/
++      copy ${CMAKE_CURRENT_SOURCE_DIR}/../../src/gui.glade $<TARGET_FILE_DIR:${APP_NAME}>/gui.glade
 +)
-+
- # You can change target that renderer draws by enabling following definition.
- #
- # * USE_RENDER_TARGET
+ # Copy resource directory to build directory.
+ add_custom_command(
 diff -pruN --exclude build ./demo_clean/scripts/make_gcc ./demo_dev/scripts/make_gcc
---- ./demo_clean/scripts/make_gcc      2020-09-27 17:43:12.069477246 +0100
-+++ ./demo_dev/scripts/make_gcc        2020-07-14 15:33:09.865020790 +0100
-@@ -9,5 +9,6 @@ BUILD_PATH=$SCRIPT_PATH/../build/make_gc
- # Run CMake.
+--- ./demo_clean/scripts/make_gcc      2021-02-17 01:23:17.000000000 +0000
++++ ./demo_dev/scripts/make_gcc        2021-04-28 12:18:50.948333190 +0100
+@@ -10,4 +10,4 @@ BUILD_PATH=$SCRIPT_PATH/../build/make_gc
  cmake -S "$CMAKE_PATH" \
    -B "$BUILD_PATH" \
--  -D CMAKE_BUILD_TYPE=Release
+   -D CMAKE_BUILD_TYPE=Release
 -cd "$BUILD_PATH" && make
-+  -D CMAKE_BUILD_TYPE=Release \
-+  -D USE_AVX_INSTRUCTIONS=1
 +cd "$BUILD_PATH" && make -j4
 diff -pruN --exclude build ./demo_clean/src/CMakeLists.txt ./demo_dev/src/CMakeLists.txt
---- ./demo_clean/src/CMakeLists.txt    2020-09-27 17:43:12.081477263 +0100
-+++ ./demo_dev/src/CMakeLists.txt      2020-07-11 17:39:18.358435702 +0100
-@@ -19,6 +19,4 @@ target_sources(${APP_NAME}
+--- ./demo_clean/src/CMakeLists.txt    2021-02-17 01:23:17.000000000 +0000
++++ ./demo_dev/src/CMakeLists.txt      2021-04-28 12:21:56.795134807 +0100
+@@ -6,8 +6,6 @@ target_sources(${APP_NAME}
+     ${CMAKE_CURRENT_SOURCE_DIR}/LAppDefine.hpp
+     ${CMAKE_CURRENT_SOURCE_DIR}/LAppDelegate.cpp
+     ${CMAKE_CURRENT_SOURCE_DIR}/LAppDelegate.hpp
+-    ${CMAKE_CURRENT_SOURCE_DIR}/LAppWavFileHandler.cpp
+-    ${CMAKE_CURRENT_SOURCE_DIR}/LAppWavFileHandler.hpp
+     ${CMAKE_CURRENT_SOURCE_DIR}/LAppLive2DManager.cpp
+     ${CMAKE_CURRENT_SOURCE_DIR}/LAppLive2DManager.hpp
+     ${CMAKE_CURRENT_SOURCE_DIR}/LAppModel.cpp
+@@ -21,6 +19,4 @@ target_sources(${APP_NAME}
      ${CMAKE_CURRENT_SOURCE_DIR}/LAppView.cpp
      ${CMAKE_CURRENT_SOURCE_DIR}/LAppView.hpp
      ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp
 -    ${CMAKE_CURRENT_SOURCE_DIR}/TouchManager.cpp
 -    ${CMAKE_CURRENT_SOURCE_DIR}/TouchManager.hpp
  )
+diff -pruN --exclude build ./demo_clean/src/LAppDefine.cpp ./demo_dev/src/LAppDefine.cpp
+--- ./demo_clean/src/LAppDefine.cpp    2021-02-17 01:23:17.000000000 +0000
++++ ./demo_dev/src/LAppDefine.cpp      2021-04-28 12:18:50.948333190 +0100
+@@ -64,11 +64,11 @@ namespace LAppDefine {
+     const csmInt32 PriorityForce = 3;
+     // デバッグ用ログの表示オプション
+-    const csmBool DebugLogEnable = true;
++    const csmBool DebugLogEnable = false;
+     const csmBool DebugTouchLogEnable = false;
+     // Frameworkから出力するログのレベル設定
+-    const CubismFramework::Option::LogLevel CubismLoggingLevel = CubismFramework::Option::LogLevel_Verbose;
++    const CubismFramework::Option::LogLevel CubismLoggingLevel = CubismFramework::Option::LogLevel_Warning;
+     // デフォルトのレンダーターゲットサイズ
+     const csmInt32 RenderTargetWidth = 1900;
 diff -pruN --exclude build ./demo_clean/src/LAppDelegate.cpp ./demo_dev/src/LAppDelegate.cpp
---- ./demo_clean/src/LAppDelegate.cpp  2020-09-27 17:43:12.081477263 +0100
-+++ ./demo_dev/src/LAppDelegate.cpp    2020-07-11 17:35:02.414902548 +0100
+--- ./demo_clean/src/LAppDelegate.cpp  2021-02-17 01:23:17.000000000 +0000
++++ ./demo_dev/src/LAppDelegate.cpp    2021-04-28 12:18:50.948333190 +0100
 @@ -45,7 +45,8 @@ void LAppDelegate::ReleaseInstance()
      s_instance = NULL;
  }
@@ -213,8 +229,8 @@ diff -pruN --exclude build ./demo_clean/src/LAppDelegate.cpp ./demo_dev/src/LApp
  
  Csm::csmVector<string> LAppDelegate::Split(const std::string& baseString, char delimiter)
 diff -pruN --exclude build ./demo_clean/src/LAppDelegate.hpp ./demo_dev/src/LAppDelegate.hpp
---- ./demo_clean/src/LAppDelegate.hpp  2020-09-27 17:43:12.081477263 +0100
-+++ ./demo_dev/src/LAppDelegate.hpp    2020-07-11 17:34:40.778602504 +0100
+--- ./demo_clean/src/LAppDelegate.hpp  2021-02-17 01:23:17.000000000 +0000
++++ ./demo_dev/src/LAppDelegate.hpp    2021-04-28 12:18:50.948333190 +0100
 @@ -40,7 +40,8 @@ public:
      /**
      * @brief   APPに必要なものを初期化する。
@@ -289,9 +305,9 @@ diff -pruN --exclude build ./demo_clean/src/LAppDelegate.hpp ./demo_dev/src/LApp
 -
 -};
 diff -pruN --exclude build ./demo_clean/src/LAppLive2DManager.cpp ./demo_dev/src/LAppLive2DManager.cpp
---- ./demo_clean/src/LAppLive2DManager.cpp     2020-09-27 17:43:12.081477263 +0100
-+++ ./demo_dev/src/LAppLive2DManager.cpp       2020-07-11 23:20:11.548419176 +0100
-@@ -52,9 +52,10 @@ void LAppLive2DManager::ReleaseInstance(
+--- ./demo_clean/src/LAppLive2DManager.cpp     2021-02-17 01:23:17.000000000 +0000
++++ ./demo_dev/src/LAppLive2DManager.cpp       2021-04-28 12:24:45.405646016 +0100
+@@ -52,11 +52,11 @@ void LAppLive2DManager::ReleaseInstance(
  
  LAppLive2DManager::LAppLive2DManager()
      : _viewMatrix(NULL)
@@ -300,11 +316,13 @@ diff -pruN --exclude build ./demo_clean/src/LAppLive2DManager.cpp ./demo_dev/src
 +    , _translateX(0.0f)
 +    , _translateY(0.0f)
  {
+     _viewMatrix = new CubismMatrix44();
+-
 -    ChangeScene(_sceneIndex);
  }
  
  LAppLive2DManager::~LAppLive2DManager()
-@@ -98,26 +99,6 @@ void LAppLive2DManager::OnTap(csmFloat32
+@@ -100,26 +100,6 @@ void LAppLive2DManager::OnTap(csmFloat32
      {
          LAppPal::PrintLog("[APP]tap point: {x:%.2f y:%.2f}", x, y);
      }
@@ -331,18 +349,25 @@ diff -pruN --exclude build ./demo_clean/src/LAppLive2DManager.cpp ./demo_dev/src
  }
  
  void LAppLive2DManager::OnUpdate() const
-@@ -125,7 +106,9 @@ void LAppLive2DManager::OnUpdate() const
-     CubismMatrix44 projection;
-     int width, height;
-     glfwGetWindowSize(LAppDelegate::GetInstance()->GetWindow(), &width, &height);
--    projection.Scale(1.0f, static_cast<float>(width) / static_cast<float>(height));
-+    projection.Scale(_projScaleFactor,
-+                     _projScaleFactor * static_cast<float>(width) / static_cast<float>(height));
-+    projection.Translate(_translateX, _translateY);
+@@ -136,12 +116,15 @@ void LAppLive2DManager::OnUpdate() const
+         {
+             // 横に長いモデルを縦長ウィンドウに表示する際モデルの横サイズでscaleを算出する
+             model->GetModelMatrix()->SetWidth(2.0f);
+-            projection.Scale(1.0f, static_cast<float>(width) / static_cast<float>(height));
++            projection.Scale(_projScaleFactor,
++                             _projScaleFactor * static_cast<float>(width) / static_cast<float>(height));
+         }
+         else
+         {
+-            projection.Scale(static_cast<float>(height) / static_cast<float>(width), 1.0f);
++            projection.Scale(_projScaleFactor * static_cast<float>(height) / static_cast<float>(width),
++                             _projScaleFactor);
+         }
++        projection.Translate(_translateX, _translateY);
  
-     if (_viewMatrix != NULL)
-     {
-@@ -148,26 +131,10 @@ void LAppLive2DManager::OnUpdate() const
+         // 必要があればここで乗算
+         if (_viewMatrix != NULL)
+@@ -158,30 +141,14 @@ void LAppLive2DManager::OnUpdate() const
      }
  }
  
@@ -353,7 +378,7 @@ diff -pruN --exclude build ./demo_clean/src/LAppLive2DManager.cpp ./demo_dev/src
 -}
 -
 -void LAppLive2DManager::ChangeScene(Csm::csmInt32 index)
-+void LAppLive2DManager::SetModel(std::string modelName)
++void LAppLive2DManager::SetModel(std::string modelName, bool useOldParamId)
  {
 -    _sceneIndex = index;
 -    if (DebugLogEnable)
@@ -372,16 +397,30 @@ diff -pruN --exclude build ./demo_clean/src/LAppLive2DManager.cpp ./demo_dev/src
      modelJsonName += ".model3.json";
  
      ReleaseAllModel();
-@@ -215,3 +182,20 @@ csmUint32 LAppLive2DManager::GetModelNum
- {
-     return _models.GetSize();
+-    _models.PushBack(new LAppModel());
++    _models.PushBack(new LAppModel(useOldParamId));
+     _models[0]->LoadAssets(modelPath.c_str(), modelJsonName.c_str());
+     /*
+@@ -203,7 +170,7 @@ void LAppLive2DManager::ChangeScene(Csm:
+ #if defined(USE_RENDER_TARGET) || defined(USE_MODEL_RENDER_TARGET)
+         // モデル個別にαを付けるサンプルとして、もう1体モデルを作成し、少し位置をずらす
+-        _models.PushBack(new LAppModel());
++        _models.PushBack(new LAppModel(useOldParamId));
+         _models[1]->LoadAssets(modelPath.c_str(), modelJsonName.c_str());
+         _models[1]->GetModelMatrix()->TranslateX(0.2f);
+ #endif
+@@ -232,3 +199,20 @@ void LAppLive2DManager::SetViewMatrix(Cu
+         _viewMatrix->GetArray()[i] = m->GetArray()[i];
+     }
  }
 +
-+void LAppLive2DManager::SetFacialLandmarkDetector(FacialLandmarkDetector *detector)
++void LAppLive2DManager::SetTracker(MouseCursorTracker *tracker)
 +{
 +    for (auto it = _models.Begin(); it != _models.End(); ++it)
 +    {
-+        (*it)->SetFacialLandmarkDetector(detector);
++        (*it)->SetTracker(tracker);
 +    }
 +}
 +
@@ -394,8 +433,8 @@ diff -pruN --exclude build ./demo_clean/src/LAppLive2DManager.cpp ./demo_dev/src
 +    _translateY = translateY;
 +}
 diff -pruN --exclude build ./demo_clean/src/LAppLive2DManager.hpp ./demo_dev/src/LAppLive2DManager.hpp
---- ./demo_clean/src/LAppLive2DManager.hpp     2020-09-27 17:43:12.069477246 +0100
-+++ ./demo_dev/src/LAppLive2DManager.hpp       2020-07-11 23:21:17.969484538 +0100
+--- ./demo_clean/src/LAppLive2DManager.hpp     2021-02-17 01:23:17.000000000 +0000
++++ ./demo_dev/src/LAppLive2DManager.hpp       2021-04-28 12:18:50.948333190 +0100
 @@ -6,12 +6,15 @@
   */
  #pragma once
@@ -407,12 +446,12 @@ diff -pruN --exclude build ./demo_clean/src/LAppLive2DManager.hpp ./demo_dev/src
  
  class LAppModel;
  
-+class FacialLandmarkDetector;
++class MouseCursorTracker;
 +
  /**
  * @brief サンプルアプリケーションにおいてCubismModelを管理するクラス<br>
  *         モデル生成と破棄、タップイベントの処理、モデル切り替えを行う。
-@@ -72,16 +75,12 @@ public:
+@@ -72,16 +75,14 @@ public:
      void OnUpdate() const;
  
      /**
@@ -430,21 +469,23 @@ diff -pruN --exclude build ./demo_clean/src/LAppLive2DManager.hpp ./demo_dev/src
 +     *
 +     * @param[in] modelName : Name of model, should be the same for both
 +     *                        the directory and the model3.json file
++     * @param[in] useOldParamId : If true, translate new (Cubism 3+)
++     *                            parameter IDs to old (Cubism 2.1) ones
 +     */
-+    void SetModel(std::string modelName);
++    void SetModel(std::string modelName, bool useOldParamId);
  
      /**
       * @brief   モデル個数を得る
-@@ -89,6 +88,24 @@ public:
+@@ -94,6 +95,24 @@ public:
       */
-     Csm::csmUint32 GetModelNum() const;
+     void SetViewMatrix(Live2D::Cubism::Framework::CubismMatrix44* m);
  
 +    /**
-+     * @brief Set the pointer to the FacialLandmarkDetector instance
++     * @brief Set the pointer to the MouseCursorTracker instance
 +     *
-+     * @param[in] detector : Pointer to FacialLandmarkDetector instance
++     * @param[in] tracker : Pointer to MouseCursorTracker instance
 +     */
-+    void SetFacialLandmarkDetector(FacialLandmarkDetector *detector);
++    void SetTracker(MouseCursorTracker *tracker);
 +
 +    /**
 +     * @brief Set projection scale factor and translation parameters
@@ -460,7 +501,7 @@ diff -pruN --exclude build ./demo_clean/src/LAppLive2DManager.hpp ./demo_dev/src
  private:
      /**
      * @brief  コンストラクタ
-@@ -102,5 +119,8 @@ private:
+@@ -107,5 +126,8 @@ private:
  
      Csm::CubismMatrix44*        _viewMatrix; ///< モデル描画に用いるView行列
      Csm::csmVector<LAppModel*>  _models; ///< モデルインスタンスのコンテナ
@@ -471,65 +512,61 @@ diff -pruN --exclude build ./demo_clean/src/LAppLive2DManager.hpp ./demo_dev/src
 +    float _translateY;
  };
 diff -pruN --exclude build ./demo_clean/src/LAppModel.cpp ./demo_dev/src/LAppModel.cpp
---- ./demo_clean/src/LAppModel.cpp     2020-09-27 17:43:12.069477246 +0100
-+++ ./demo_dev/src/LAppModel.cpp       2020-09-27 17:40:16.401166244 +0100
-@@ -21,6 +21,8 @@
+--- ./demo_clean/src/LAppModel.cpp     2021-02-17 01:23:17.000000000 +0000
++++ ./demo_dev/src/LAppModel.cpp       2021-04-28 12:26:56.699586813 +0100
+@@ -21,6 +21,10 @@
  #include "LAppTextureManager.hpp"
  #include "LAppDelegate.hpp"
  
-+#include "facial_landmark_detector.h"
++#include "mouse_cursor_tracker.h"
++
++#include <iostream>
 +
  using namespace Live2D::Cubism::Framework;
  using namespace Live2D::Cubism::Framework::DefaultParameterId;
  using namespace LAppDefine;
-@@ -128,30 +130,6 @@ void LAppModel::SetupModel(ICubismModelS
-         DeleteBuffer(buffer, path.GetRawString());
+@@ -45,22 +49,24 @@ namespace {
      }
+ }
  
--    //Expression
--    if (_modelSetting->GetExpressionCount() > 0)
--    {
--        const csmInt32 count = _modelSetting->GetExpressionCount();
--        for (csmInt32 i = 0; i < count; i++)
--        {
--            csmString name = _modelSetting->GetExpressionName(i);
--            csmString path = _modelSetting->GetExpressionFileName(i);
--            path = _modelHomeDir + path;
--
--            buffer = CreateBuffer(path.GetRawString(), &size);
--            ACubismMotion* motion = LoadExpression(buffer, size, name.GetRawString());
--
--            if (_expressions[name] != NULL)
--            {
--                ACubismMotion::Delete(_expressions[name]);
--                _expressions[name] = NULL;
--            }
--            _expressions[name] = motion;
--
--            DeleteBuffer(buffer, path.GetRawString());
--        }
--    }
--
-     //Physics
-     if (strcmp(_modelSetting->GetPhysicsFileName(), "") != 0)
+-LAppModel::LAppModel()
++LAppModel::LAppModel(bool useOldParamId)
+     : CubismUserModel()
+     , _modelSetting(NULL)
+     , _userTimeSeconds(0.0f)
++    , _tracker(nullptr)
++    , _useOldParamId(useOldParamId)
+ {
+     if (DebugLogEnable)
      {
-@@ -214,15 +192,6 @@ void LAppModel::SetupModel(ICubismModelS
-         }
+         _debugMode = true;
      }
  
--    // LipSyncIds
--    {
--        csmInt32 lipSyncIdCount = _modelSetting->GetLipSyncParameterCount();
--        for (csmInt32 i = 0; i < lipSyncIdCount; ++i)
--        {
--            _lipSyncIds.PushBack(_modelSetting->GetLipSyncParameterId(i));
--        }
--    }
--
-     //Layout
-     csmMap<csmString, csmFloat32> layout;
-     _modelSetting->GetLayoutMap(layout);
-@@ -335,59 +304,57 @@ void LAppModel::Update()
+-    _idParamAngleX = CubismFramework::GetIdManager()->GetId(ParamAngleX);
+-    _idParamAngleY = CubismFramework::GetIdManager()->GetId(ParamAngleY);
+-    _idParamAngleZ = CubismFramework::GetIdManager()->GetId(ParamAngleZ);
+-    _idParamBodyAngleX = CubismFramework::GetIdManager()->GetId(ParamBodyAngleX);
+-    _idParamEyeBallX = CubismFramework::GetIdManager()->GetId(ParamEyeBallX);
+-    _idParamEyeBallY = CubismFramework::GetIdManager()->GetId(ParamEyeBallY);
++    _idParamAngleX = CubismFramework::GetIdManager()->GetId(_(ParamAngleX));
++    _idParamAngleY = CubismFramework::GetIdManager()->GetId(_(ParamAngleY));
++    _idParamAngleZ = CubismFramework::GetIdManager()->GetId(_(ParamAngleZ));
++    _idParamBodyAngleX = CubismFramework::GetIdManager()->GetId(_(ParamBodyAngleX));
++    _idParamEyeBallX = CubismFramework::GetIdManager()->GetId(_(ParamEyeBallX));
++    _idParamEyeBallY = CubismFramework::GetIdManager()->GetId(_(ParamEyeBallY));
+ }
+ LAppModel::~LAppModel()
+@@ -190,7 +196,7 @@ void LAppModel::SetupModel(ICubismModelS
+         breathParameters.PushBack(CubismBreath::BreathParameterData(_idParamAngleY, 0.0f, 8.0f, 3.5345f, 0.5f));
+         breathParameters.PushBack(CubismBreath::BreathParameterData(_idParamAngleZ, 0.0f, 10.0f, 5.5345f, 0.5f));
+         breathParameters.PushBack(CubismBreath::BreathParameterData(_idParamBodyAngleX, 0.0f, 4.0f, 15.5345f, 0.5f));
+-        breathParameters.PushBack(CubismBreath::BreathParameterData(CubismFramework::GetIdManager()->GetId(ParamBreath), 0.5f, 0.5f, 3.2345f, 0.5f));
++        breathParameters.PushBack(CubismBreath::BreathParameterData(CubismFramework::GetIdManager()->GetId(_(ParamBreath)), 0.5f, 0.5f, 3.2345f, 0.5f));
+         _breath->SetParameters(breathParameters);
+     }
+@@ -335,83 +341,118 @@ void LAppModel::Update()
      const csmFloat32 deltaTimeSeconds = LAppPal::GetDeltaTime();
      _userTimeSeconds += deltaTimeSeconds;
  
@@ -548,157 +585,291 @@ diff -pruN --exclude build ./demo_clean/src/LAppModel.cpp ./demo_dev/src/LAppMod
 -        StartRandomMotion(MotionGroupIdle, PriorityIdle);
 -    }
 -    else
-+    if (_detector)
++    if (_tracker)
      {
 -        motionUpdated = _motionManager->UpdateMotion(_model, deltaTimeSeconds); // モーションを更新
 -    }
 -    _model->SaveParameters(); // 状態を保存
 -    //-----------------------------------------------------------------
 +        auto idMan = CubismFramework::GetIdManager();
-+        auto params = _detector->getParams();
++        auto params = _tracker->getParams();
  
 -    // まばたき
 -    if (!motionUpdated)
 -    {
 -        if (_eyeBlink != NULL)
-+        // NOTE: Apparently, this LoadParameters/SaveParameters pair
-+        // is needed for auto breath to work.
 +        _model->LoadParameters(); // 前回セーブされた状態をロード
-+        if (_motionManager->IsFinished() && params.randomMotion)
++
++        int paramsMotionPriority = static_cast<int>(params.motionPriority);
++
++        if (paramsMotionPriority != PriorityNone)
          {
 -            // メインモーションの更新がないとき
 -            _eyeBlink->UpdateParameters(_model, deltaTimeSeconds); // 目パチ
++            StartMotion(params.motionGroup.c_str(), params.motionNumber,
++                        paramsMotionPriority);
++        }
++        else if (params.randomIdleMotion && _motionManager->IsFinished())
++        {
 +            // モーションの再生がない場合、待機モーションの中からランダムで再生する
 +            StartRandomMotion(MotionGroupIdle, PriorityIdle);
          }
 -    }
--
 -    if (_expressionManager != NULL)
 -    {
 -        _expressionManager->UpdateMotion(_model, deltaTimeSeconds); // 表情でパラメータ更新(相対変化)
 -    }
--
++        // FIXME pose does not return to normal after motion
++        // if we don't have randomIdleMotion set
++        else
++        {
++            _motionManager->UpdateMotion(_model, deltaTimeSeconds); // モーションを更新
++        }
++        _model->SaveParameters(); // 状態を保存
 -    //ドラッグによる変化
 -    //ドラッグによる顔の向きの調整
 -    _model->AddParameterValue(_idParamAngleX, _dragX * 30); // -30から30の値を加える
 -    _model->AddParameterValue(_idParamAngleY, _dragY * 30);
 -    _model->AddParameterValue(_idParamAngleZ, _dragX * _dragY * -30);
--
--    //ドラッグによる体の向きの調整
--    _model->AddParameterValue(_idParamBodyAngleX, _dragX * 10); // -10から10の値を加える
-+        else
++        if (params.expression != "")
 +        {
-+            _motionManager->UpdateMotion(_model, deltaTimeSeconds); // モーションを更新
++            SetExpression(params.expression.c_str());
++        }
++        if (_expressionManager != NULL)
++        {
++            _expressionManager->UpdateMotion(_model, deltaTimeSeconds); // 表情でパラメータ更新(相対変化)
 +        }
-+        _model->SaveParameters(); // 状態を保存
+-    //ドラッグによる体の向きの調整
+-    _model->AddParameterValue(_idParamBodyAngleX, _dragX * 10); // -10から10の値を加える
++        bool autoBlink = params.autoBlink && _eyeBlink;
++        auto eyeLOpenIt = params.live2d.find("ParamEyeLOpen");
++        auto eyeROpenIt = params.live2d.find("ParamEyeROpen");
  
 -    //ドラッグによる目の向きの調整
 -    _model->AddParameterValue(_idParamEyeBallX, _dragX); // -1から1の値を加える
 -    _model->AddParameterValue(_idParamEyeBallY, _dragY);
++        if (autoBlink)
++        {
++            // Handle blink first
++            _eyeBlink->UpdateParameters(_model, deltaTimeSeconds);
++        }
  
 -    // 呼吸など
 -    if (_breath != NULL)
 -    {
 -        _breath->UpdateParameters(_model, deltaTimeSeconds);
-+        if (params.autoBlink && _eyeBlink)
+-    }
++        if (eyeLOpenIt != params.live2d.end())
 +        {
-+            _eyeBlink->UpdateParameters(_model, deltaTimeSeconds);
++            // If value specified, override blinking
++            _model->SetParameterValue(idMan->GetId(_("ParamEyeLOpen")),
++                                      eyeLOpenIt->second);
++        }
++        else if (!autoBlink)
++        {
++            // If no value specified and no auto blink, set to 1
++            _model->SetParameterValue(idMan->GetId(_("ParamEyeLOpen")), 1);
+-    // 物理演算の設定
+-    if (_physics != NULL)
+-    {
+-        _physics->Evaluate(_model, deltaTimeSeconds);
+-    }
++        }
+-    // リップシンクの設定
+-    if (_lipSync)
+-    {
+-        // リアルタイムでリップシンクを行う場合、システムから音量を取得して0〜1の範囲で値を入力します。
+-        csmFloat32 value = 0.0f;
++        if (eyeROpenIt != params.live2d.end())
++        {
++            _model->SetParameterValue(idMan->GetId(_("ParamEyeROpen")),
++                                      eyeROpenIt->second);
++        }
++        else if (!autoBlink)
++        {
++            _model->SetParameterValue(idMan->GetId(_("ParamEyeROpen")), 1);
++        }
+-        // 状態更新/RMS値取得
+-        _wavFileHandler.Update(deltaTimeSeconds);
+-        value = _wavFileHandler.GetRms();
+-        for (csmUint32 i = 0; i < _lipSyncIds.GetSize(); ++i)
++        if (params.useLipSync && _lipSync)
+         {
+-            _model->AddParameterValue(_lipSyncIds[i], value, 0.8f);
++            csmFloat32 value = params.lipSyncParam; // 0 to 1
++
++            for (csmUint32 i = 0; i < _lipSyncIds.GetSize(); ++i)
++            {
++                _model->AddParameterValue(_lipSyncIds[i], value, 0.8f);
++            }
 +        }
 +        else
 +        {
-+            _model->SetParameterValue(idMan->GetId("ParamEyeLOpen"),
-+                                      params.leftEyeOpenness);
-+            _model->SetParameterValue(idMan->GetId("ParamEyeROpen"),
-+                                      params.rightEyeOpenness);
++            _model->SetParameterValue(idMan->GetId(_("ParamMouthOpenY")),
++                                      params.live2d["ParamMouthOpenY"]);
++        }
++
++        for (auto const &entry : params.live2d)
++        {
++            std::string key = entry.first;
++            double val = entry.second;
++
++            if (key != "ParamEyeLOpen" && key != "ParamEyeROpen" &&
++                key != "ParamMouthOpenY")
++            {
++                _model->SetParameterValue(idMan->GetId(_(key)), val);
++            }
 +        }
-+        _model->SetParameterValue(idMan->GetId("ParamMouthForm"),
-+                                  params.mouthForm);
-+        _model->SetParameterValue(idMan->GetId("ParamMouthOpenY"),
-+                                  params.mouthOpenness);
-+        _model->SetParameterValue(idMan->GetId("ParamEyeLSmile"),
-+                                  params.leftEyeSmile);
-+        _model->SetParameterValue(idMan->GetId("ParamEyeRSmile"),
-+                                  params.rightEyeSmile);
-+        _model->SetParameterValue(idMan->GetId("ParamAngleX"),
-+                                  params.faceXAngle);
-+        _model->SetParameterValue(idMan->GetId("ParamAngleY"),
-+                                  params.faceYAngle);
-+        _model->SetParameterValue(idMan->GetId("ParamAngleZ"),
-+                                  params.faceZAngle);
++
 +        if (params.autoBreath && _breath)
 +        {
 +            // Note: _model->LoadParameters and SaveParameters is needed
 +            // before - see above.
 +            _breath->UpdateParameters(_model, deltaTimeSeconds);
-+        }
-     }
-     // 物理演算の設定
-@@ -396,17 +363,6 @@ void LAppModel::Update()
-         _physics->Evaluate(_model, deltaTimeSeconds);
+         }
      }
  
--    // リップシンクの設定
--    if (_lipSync)
--    {
--        csmFloat32 value = 0; // リアルタイムでリップシンクを行う場合、システムから音量を取得して0〜1の範囲で値を入力します。
--
--        for (csmUint32 i = 0; i < _lipSyncIds.GetSize(); ++i)
--        {
--            _model->AddParameterValue(_lipSyncIds[i], value, 0.8f);
--        }
--    }
--
++    // 物理演算の設定
++    if (_physics != NULL)
++    {
++        _physics->Evaluate(_model, deltaTimeSeconds);
++    }
++
      // ポーズの設定
      if (_pose != NULL)
      {
-@@ -626,3 +582,9 @@ Csm::Rendering::CubismOffscreenFrame_Ope
+@@ -480,7 +521,6 @@ CubismMotionQueueEntryHandle LAppModel::
+     {
+         csmString path = voice;
+         path = _modelHomeDir + path;
+-        _wavFileHandler.Start(path);
+     }
+     if (_debugMode)
+@@ -632,3 +672,42 @@ Csm::Rendering::CubismOffscreenFrame_Ope
  {
      return _renderBuffer;
  }
 +
-+void LAppModel::SetFacialLandmarkDetector(FacialLandmarkDetector *detector)
++void LAppModel::SetTracker(MouseCursorTracker *tracker)
++{
++    _tracker = tracker;
++}
++
++Csm::ICubismModelSetting* LAppModel::GetModelSetting(void) const
 +{
-+    _detector = detector;
++    return _modelSetting;
++}
++
++Csm::csmString LAppModel::_(std::string s)
++{
++    std::string ans;
++    if (_useOldParamId)
++    {
++        if (s == "ParamTere")
++        {
++            ans = "PARAM_CHEEK";
++        }
++        else
++        {
++            for (size_t i = 0; i < s.size(); i++)
++            {
++                if (std::isupper(s[i]) && i != 0)
++                {
++                    ans += '_';
++                }
++                ans += std::toupper(s[i]);
++            }
++        }
++    }
++    else
++    {
++        ans = s;
++    }
++    return csmString(ans.c_str());
 +}
 +
 diff -pruN --exclude build ./demo_clean/src/LAppModel.hpp ./demo_dev/src/LAppModel.hpp
---- ./demo_clean/src/LAppModel.hpp     2020-09-27 17:43:12.081477263 +0100
-+++ ./demo_dev/src/LAppModel.hpp       2020-07-11 15:40:18.977286166 +0100
-@@ -13,6 +13,7 @@
+--- ./demo_clean/src/LAppModel.hpp     2021-02-17 01:23:17.000000000 +0000
++++ ./demo_dev/src/LAppModel.hpp       2021-04-28 12:27:55.836457680 +0100
+@@ -13,7 +13,7 @@
  #include <Type/csmRectF.hpp>
  #include <Rendering/OpenGL/CubismOffscreenSurface_OpenGLES2.hpp>
  
-+#include "facial_landmark_detector.h"
+-#include "LAppWavFileHandler.hpp"
++#include "mouse_cursor_tracker.h"
  
  /**
   * @brief ユーザーが実際に使用するモデルの実装クラス<br>
-@@ -113,6 +114,13 @@ public:
+@@ -25,8 +25,11 @@ class LAppModel : public Csm::CubismUser
+ public:
+     /**
+      * @brief コンストラクタ
++     *
++     * @param[in] useOldParamId : If true, translate new (Cubism 3+)
++     *                            parameter IDs to old (Cubism 2.1)  ones
+      */
+-    LAppModel();
++    LAppModel(bool useOldParamId);
+     /**
+      * @brief デストラクタ
+@@ -114,6 +117,15 @@ public:
       */
      Csm::Rendering::CubismOffscreenFrame_OpenGLES2& GetRenderBuffer();
  
 +    /**
-+     * @brief Set the pointer to the FacialLandmarkDetector instance
++     * @brief Set the pointer to the MouseCursorTracker instance
 +     *
-+     * @param[in] detector : Pointer to FacialLandmarkDetector instance
++     * @param[in] tracker : Pointer to MouseCursorTracker instance
 +     */
-+    void SetFacialLandmarkDetector(FacialLandmarkDetector *detector);
++    void SetTracker(MouseCursorTracker *tracker);
++
++    Csm::ICubismModelSetting* GetModelSetting(void) const;
 +
  protected:
      /**
       *  @brief  モデルを描画する処理。モデルを描画する空間のView-Projection行列を渡す。
-@@ -183,6 +191,8 @@ private:
+@@ -167,6 +179,17 @@ private:
+     */
+     void ReleaseExpressions();
++    /**
++     * @brief Translate new (Cubism 3+) parameter IDs to old (Cubism 2.1) ones
++     *
++     * @param[in] s : New parameter ID
++     *
++     * @return Old parameter ID
++     */
++    Csm::csmString _(std::string s);
++
++    bool _useOldParamId;
++
+     Csm::ICubismModelSetting* _modelSetting; ///< モデルセッティング情報
+     Csm::csmString _modelHomeDir; ///< モデルセッティングが置かれたディレクトリ
+     Csm::csmFloat32 _userTimeSeconds; ///< デルタ時間の積算値[秒]
+@@ -183,9 +206,9 @@ private:
+     const Csm::CubismId* _idParamEyeBallX; ///< パラメータID: ParamEyeBallX
      const Csm::CubismId* _idParamEyeBallY; ///< パラメータID: ParamEyeBallXY
  
+-    LAppWavFileHandler _wavFileHandler; ///< wavファイルハンドラ
+-
      Csm::Rendering::CubismOffscreenFrame_OpenGLES2 _renderBuffer;   ///< フレームバッファ以外の描画先
 +
-+    FacialLandmarkDetector *_detector;
++    MouseCursorTracker *_tracker;
  };
  
  
 diff -pruN --exclude build ./demo_clean/src/LAppPal.cpp ./demo_dev/src/LAppPal.cpp
---- ./demo_clean/src/LAppPal.cpp       2020-09-27 17:43:12.081477263 +0100
-+++ ./demo_dev/src/LAppPal.cpp 2020-07-11 23:29:09.084910139 +0100
+--- ./demo_clean/src/LAppPal.cpp       2021-02-17 01:23:17.000000000 +0000
++++ ./demo_dev/src/LAppPal.cpp 2021-04-28 12:18:50.952333251 +0100
 @@ -6,6 +6,7 @@
   */
  
@@ -707,7 +878,15 @@ diff -pruN --exclude build ./demo_clean/src/LAppPal.cpp ./demo_dev/src/LAppPal.c
  #include <stdio.h>
  #include <stdlib.h>
  #include <stdarg.h>
-@@ -45,10 +46,7 @@ csmByte* LAppPal::LoadFileAsBytes(const
+@@ -36,7 +37,6 @@ csmByte* LAppPal::LoadFileAsBytes(const
+     if (stat(path, &statBuf) == 0)
+     {
+         size = statBuf.st_size;
+-        PrintLog(path);
+     }
+     std::fstream file;
+@@ -45,10 +45,7 @@ csmByte* LAppPal::LoadFileAsBytes(const
      file.open(path, std::ios::in | std::ios::binary);
      if (!file.is_open())
      {
@@ -720,8 +899,8 @@ diff -pruN --exclude build ./demo_clean/src/LAppPal.cpp ./demo_dev/src/LAppPal.c
      }
      file.read(buf, size);
 diff -pruN --exclude build ./demo_clean/src/LAppTextureManager.cpp ./demo_dev/src/LAppTextureManager.cpp
---- ./demo_clean/src/LAppTextureManager.cpp    2020-09-27 17:43:12.085477268 +0100
-+++ ./demo_dev/src/LAppTextureManager.cpp      2020-07-11 22:22:18.004965003 +0100
+--- ./demo_clean/src/LAppTextureManager.cpp    2021-02-17 01:23:17.000000000 +0000
++++ ./demo_dev/src/LAppTextureManager.cpp      2021-04-28 12:18:50.952333251 +0100
 @@ -96,6 +96,46 @@ LAppTextureManager::TextureInfo* LAppTex
  
  }
@@ -770,8 +949,8 @@ diff -pruN --exclude build ./demo_clean/src/LAppTextureManager.cpp ./demo_dev/sr
  {
      for (Csm::csmUint32 i = 0; i < _textures.GetSize(); i++)
 diff -pruN --exclude build ./demo_clean/src/LAppTextureManager.hpp ./demo_dev/src/LAppTextureManager.hpp
---- ./demo_clean/src/LAppTextureManager.hpp    2020-09-27 17:43:12.069477246 +0100
-+++ ./demo_dev/src/LAppTextureManager.hpp      2020-07-11 17:36:31.180131039 +0100
+--- ./demo_clean/src/LAppTextureManager.hpp    2021-02-17 01:23:17.000000000 +0000
++++ ./demo_dev/src/LAppTextureManager.hpp      2021-04-28 12:18:50.952333251 +0100
 @@ -72,6 +72,8 @@ public:
      */
      TextureInfo* CreateTextureFromPngFile(std::string fileName);
@@ -782,8 +961,8 @@ diff -pruN --exclude build ./demo_clean/src/LAppTextureManager.hpp ./demo_dev/sr
      * @brief 画像の解放
      *
 diff -pruN --exclude build ./demo_clean/src/LAppView.cpp ./demo_dev/src/LAppView.cpp
---- ./demo_clean/src/LAppView.cpp      2020-09-27 17:43:12.085477268 +0100
-+++ ./demo_dev/src/LAppView.cpp        2020-07-11 17:38:06.905451955 +0100
+--- ./demo_clean/src/LAppView.cpp      2021-02-17 01:23:17.000000000 +0000
++++ ./demo_dev/src/LAppView.cpp        2021-04-28 12:18:50.952333251 +0100
 @@ -13,7 +13,6 @@
  #include "LAppLive2DManager.hpp"
  #include "LAppTextureManager.hpp"
@@ -821,7 +1000,7 @@ diff -pruN --exclude build ./demo_clean/src/LAppView.cpp ./demo_dev/src/LAppView
  }
  
  void LAppView::Initialize()
-@@ -97,9 +89,6 @@ void LAppView::Initialize()
+@@ -107,9 +99,6 @@ void LAppView::Initialize()
  void LAppView::Render()
  {
      _back->Render();
@@ -831,7 +1010,7 @@ diff -pruN --exclude build ./demo_clean/src/LAppView.cpp ./demo_dev/src/LAppView
  
      LAppLive2DManager* Live2DManager = LAppLive2DManager::GetInstance();
  
-@@ -139,35 +128,17 @@ void LAppView::InitializeSprite()
+@@ -151,35 +140,17 @@ void LAppView::InitializeSprite()
      glfwGetWindowSize(LAppDelegate::GetInstance()->GetWindow(), &width, &height);
  
      LAppTextureManager* textureManager = LAppDelegate::GetInstance()->GetTextureManager();
@@ -872,7 +1051,7 @@ diff -pruN --exclude build ./demo_clean/src/LAppView.cpp ./demo_dev/src/LAppView
      // 画面全体を覆うサイズ
      x = width * 0.5f;
      y = height * 0.5f;
-@@ -175,52 +146,6 @@ void LAppView::InitializeSprite()
+@@ -187,52 +158,6 @@ void LAppView::InitializeSprite()
  
  }
  
@@ -925,7 +1104,7 @@ diff -pruN --exclude build ./demo_clean/src/LAppView.cpp ./demo_dev/src/LAppView
  float LAppView::TransformViewX(float deviceX) const
  {
      float screenX = _deviceToScreen->TransformX(deviceX); // 論理座標変換した座標を取得。
-@@ -362,32 +287,4 @@ void LAppView::ResizeSprite()
+@@ -374,32 +299,4 @@ void LAppView::ResizeSprite()
              _back->ResetRect(x, y, fWidth, fHeight);
          }
      }
@@ -959,8 +1138,8 @@ diff -pruN --exclude build ./demo_clean/src/LAppView.cpp ./demo_dev/src/LAppView
 -    }
  }
 diff -pruN --exclude build ./demo_clean/src/LAppView.hpp ./demo_dev/src/LAppView.hpp
---- ./demo_clean/src/LAppView.hpp      2020-09-27 17:43:12.069477246 +0100
-+++ ./demo_dev/src/LAppView.hpp        2020-07-11 17:38:25.541708705 +0100
+--- ./demo_clean/src/LAppView.hpp      2021-02-17 01:23:17.000000000 +0000
++++ ./demo_dev/src/LAppView.hpp        2021-04-28 12:18:50.952333251 +0100
 @@ -14,7 +14,6 @@
  #include "CubismFramework.hpp"
  #include <Rendering/OpenGL/CubismOffscreenSurface_OpenGLES2.hpp>
@@ -1015,15 +1194,18 @@ diff -pruN --exclude build ./demo_clean/src/LAppView.hpp ./demo_dev/src/LAppView
      // レンダリング先を別ターゲットにする方式の場合に使用
      LAppSprite* _renderSprite;                                  ///< モードによっては_renderBufferのテクスチャを描画
 diff -pruN --exclude build ./demo_clean/src/main.cpp ./demo_dev/src/main.cpp
---- ./demo_clean/src/main.cpp  2020-09-27 17:43:12.069477246 +0100
-+++ ./demo_dev/src/main.cpp    2020-07-12 15:06:29.194034887 +0100
-@@ -5,18 +5,156 @@
+--- ./demo_clean/src/main.cpp  2021-02-17 01:23:17.000000000 +0000
++++ ./demo_dev/src/main.cpp    2021-04-28 12:28:55.845339613 +0100
+@@ -5,18 +5,188 @@
   * that can be found at https://www.live2d.com/eula/live2d-open-software-license-agreement_en.html.
   */
  
 +#include <thread>
 +#include <stdexcept>
 +#include <sstream>
++#include <vector>
++#include <utility>
++#include <string>
 +
 +#ifdef __cpp_lib_filesystem
 +#include <filesystem>
@@ -1033,10 +1215,11 @@ diff -pruN --exclude build ./demo_clean/src/main.cpp ./demo_dev/src/main.cpp
 +namespace fs = std::experimental::filesystem;
 +#endif
 +
-+
++#include "ICubismModelSetting.hpp"
  #include "LAppDelegate.hpp"
 +#include "LAppLive2DManager.hpp"
-+#include "facial_landmark_detector.h"
++#include "LAppModel.hpp"
++#include "mouse_cursor_tracker.h"
 +
 +struct CmdArgs
 +{
@@ -1048,7 +1231,8 @@ diff -pruN --exclude build ./demo_clean/src/main.cpp ./demo_dev/src/main.cpp
 +    float translateX;
 +    float translateY;
 +    std::string modelName;
-+    std::string cfgPath; // Path to config file for FacialLandmarkDetector
++    bool oldId; // If true, translate new (Cubism 3+) parameter IDs to old (Cubism 2.1) IDs
++    std::string cfgPath; // Path to config file for MouseCursorTracker
 +};
 +
 +CmdArgs parseArgv(int argc, char *argv[])
@@ -1058,12 +1242,13 @@ diff -pruN --exclude build ./demo_clean/src/main.cpp ./demo_dev/src/main.cpp
 +    // Set default values
 +    cmdArgs.windowWidth = 600;
 +    cmdArgs.windowHeight = 600;
-+    cmdArgs.windowTitle = "FacialLandmarksForCubism example";
++    cmdArgs.windowTitle = "MouseTrackerForCubism example";
 +    cmdArgs.rootDir = fs::current_path();
-+    cmdArgs.scaleFactor = 8.0f;
++    cmdArgs.scaleFactor = 4.5f;
 +    cmdArgs.translateX = 0.0f;
-+    cmdArgs.translateY = -2.8f;
++    cmdArgs.translateY = -3.1f;
 +    cmdArgs.modelName = "Haru";
++    cmdArgs.oldId = false;
 +    cmdArgs.cfgPath = "";
 +
 +    int i = 1;
@@ -1128,6 +1313,10 @@ diff -pruN --exclude build ./demo_clean/src/main.cpp ./demo_dev/src/main.cpp
 +        {
 +            cmdArgs.cfgPath = argv[i + 1];
 +        }
++        else if (arg == "--old-param-id" || arg == "-o")
++        {
++            cmdArgs.oldId = (argv[i + 1][0] == '1');
++        }
 +        else
 +        {
 +            throw std::runtime_error("Unrecognized argument: " + arg);
@@ -1158,23 +1347,45 @@ diff -pruN --exclude build ./demo_clean/src/main.cpp ./demo_dev/src/main.cpp
 -    LAppDelegate::GetInstance()->Run();
 +    delegate->SetRootDirectory(cmdArgs.rootDir);
 +
-+    FacialLandmarkDetector detector(cmdArgs.cfgPath);
-+
-+    std::thread detectorThread(&FacialLandmarkDetector::mainLoop,
-+                               &detector);
-+
 +    LAppLive2DManager *manager = LAppLive2DManager::GetInstance();
-+    manager->SetModel(cmdArgs.modelName);
++    manager->SetModel(cmdArgs.modelName, cmdArgs.oldId);
 +
 +    manager->SetProjectionScaleTranslate(cmdArgs.scaleFactor,
 +                                         cmdArgs.translateX,
 +                                         cmdArgs.translateY);
-+    manager->SetFacialLandmarkDetector(&detector);
++
++    LAppModel *model = manager->GetModel(0);
++    if (!model) throw std::runtime_error("model is null");
++
++    Live2D::Cubism::Framework::ICubismModelSetting *modelSetting = model->GetModelSetting();
++    if (!modelSetting) throw std::runtime_error("modelSetting is null");
++
++    std::vector<std::pair<std::string, int> > motions;
++    int motionGroupCount = modelSetting->GetMotionGroupCount();
++    for (int i = 0; i < motionGroupCount; i++)
++    {
++        const char *motionGroup = modelSetting->GetMotionGroupName(i);
++        int motionCount = modelSetting->GetMotionCount(motionGroup);
++        motions.push_back(std::make_pair(std::string(motionGroup), motionCount));
++    }
++
++    std::vector<std::string> expressions;
++    int expCount = modelSetting->GetExpressionCount();
++    for (int i = 0; i < expCount; i++)
++    {
++        const char *expName = modelSetting->GetExpressionName(i);
++        expressions.push_back(std::string(expName));
++    }
++
++    MouseCursorTracker tracker(cmdArgs.cfgPath, motions, expressions);
++
++    std::thread trackerThread(&MouseCursorTracker::mainLoop, &tracker);
++    manager->SetTracker(&tracker);
 +
 +    delegate->Run();
 +
-+    detector.stop();
-+    detectorThread.join();
++    tracker.stop();
++    trackerThread.join();
  
      return 0;
  }