945a1ceb56c14a5a7b4611463e4957152bd9ee02
[mouse-tracker-for-cubism.git] / example / demo.patch
1 diff -pruN --exclude build ./demo_clean/CMakeLists.txt ./demo_dev/CMakeLists.txt
2 --- ./demo_clean/CMakeLists.txt 2020-10-02 02:01:04.825787688 +0100
3 +++ ./demo_dev/CMakeLists.txt   2020-10-01 23:29:15.530233484 +0100
4 @@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.16)
5  # Set app name.
6  set(APP_NAME Demo)
7  # Set directory paths.
8 -set(SDK_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../../../..)
9 +set(SDK_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../CubismSdkForNative-4-r.1)
10  set(CORE_PATH ${SDK_ROOT_PATH}/Core)
11  set(FRAMEWORK_PATH ${SDK_ROOT_PATH}/Framework)
12  set(THIRD_PARTY_PATH ${SDK_ROOT_PATH}/Samples/OpenGL/thirdParty)
13 @@ -32,7 +32,7 @@ set(GLFW_INSTALL OFF CACHE BOOL "" FORCE
14  set(BUILD_UTILS OFF CACHE BOOL "" FORCE)
15  
16  # Specify version of compiler.
17 -set(CMAKE_CXX_STANDARD 14)
18 +set(CMAKE_CXX_STANDARD 17)
19  set(CMAKE_CXX_STANDARD_REQUIRED ON)
20  set(CMAKE_CXX_EXTENSIONS OFF)
21  
22 @@ -64,6 +64,9 @@ target_link_libraries(Framework Live2DCu
23  # Find opengl libraries.
24  find_package(OpenGL REQUIRED)
25  
26 +# Add MouseTrackerForCubism
27 +add_subdirectory(../.. MouseTrackerForCubism_build)
28 +
29  # Make executable app.
30  add_executable(${APP_NAME})
31  # Add source files.
32 @@ -73,9 +76,11 @@ target_link_libraries(${APP_NAME}
33    Framework
34    glfw
35    ${OPENGL_LIBRARIES}
36 +  MouseTrackerForCubism
37 +  stdc++fs
38  )
39  # Specify include directories.
40 -target_include_directories(${APP_NAME} PRIVATE ${STB_PATH})
41 +target_include_directories(${APP_NAME} PRIVATE ${STB_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/../../include)
42  
43  # Copy resource directory to build directory.
44  add_custom_command(
45 diff -pruN --exclude build ./demo_clean/scripts/make_gcc ./demo_dev/scripts/make_gcc
46 --- ./demo_clean/scripts/make_gcc       2020-10-02 02:01:04.825787688 +0100
47 +++ ./demo_dev/scripts/make_gcc 2020-10-01 23:43:42.213875065 +0100
48 @@ -10,4 +10,4 @@ BUILD_PATH=$SCRIPT_PATH/../build/make_gc
49  cmake -S "$CMAKE_PATH" \
50    -B "$BUILD_PATH" \
51    -D CMAKE_BUILD_TYPE=Release
52 -cd "$BUILD_PATH" && make
53 +cd "$BUILD_PATH" && make -j4
54 diff -pruN --exclude build ./demo_clean/src/CMakeLists.txt ./demo_dev/src/CMakeLists.txt
55 --- ./demo_clean/src/CMakeLists.txt     2020-10-02 02:01:04.829787750 +0100
56 +++ ./demo_dev/src/CMakeLists.txt       2020-10-01 22:47:24.842846271 +0100
57 @@ -19,6 +19,4 @@ target_sources(${APP_NAME}
58      ${CMAKE_CURRENT_SOURCE_DIR}/LAppView.cpp
59      ${CMAKE_CURRENT_SOURCE_DIR}/LAppView.hpp
60      ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp
61 -    ${CMAKE_CURRENT_SOURCE_DIR}/TouchManager.cpp
62 -    ${CMAKE_CURRENT_SOURCE_DIR}/TouchManager.hpp
63  )
64 diff -pruN --exclude build ./demo_clean/src/LAppDelegate.cpp ./demo_dev/src/LAppDelegate.cpp
65 --- ./demo_clean/src/LAppDelegate.cpp   2020-10-02 02:01:04.829787750 +0100
66 +++ ./demo_dev/src/LAppDelegate.cpp     2020-10-01 22:47:24.698848890 +0100
67 @@ -45,7 +45,8 @@ void LAppDelegate::ReleaseInstance()
68      s_instance = NULL;
69  }
70  
71 -bool LAppDelegate::Initialize()
72 +bool LAppDelegate::Initialize(int initWindowWidth, int initWindowHeight,
73 +                              const char *windowTitle)
74  {
75      if (DebugLogEnable)
76      {
77 @@ -63,7 +64,13 @@ bool LAppDelegate::Initialize()
78      }
79  
80      // Windowの生成_
81 -    _window = glfwCreateWindow(RenderTargetWidth, RenderTargetHeight, "SAMPLE", NULL, NULL);
82 +    _window = glfwCreateWindow(
83 +        initWindowWidth ? initWindowWidth : RenderTargetWidth,
84 +        initWindowHeight ? initWindowHeight : RenderTargetHeight,
85 +        windowTitle ? windowTitle : "SAMPLE",
86 +        NULL,
87 +        NULL);
88 +
89      if (_window == NULL)
90      {
91          if (DebugLogEnable)
92 @@ -95,10 +102,6 @@ bool LAppDelegate::Initialize()
93      glEnable(GL_BLEND);
94      glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
95  
96 -    //コールバック関数の登録
97 -    glfwSetMouseButtonCallback(_window, EventHandler::OnMouseCallBack);
98 -    glfwSetCursorPosCallback(_window, EventHandler::OnMouseCallBack);
99 -
100      // ウィンドウサイズ記憶
101      int width, height;
102      glfwGetWindowSize(LAppDelegate::GetInstance()->GetWindow(), &width, &height);
103 @@ -111,8 +114,6 @@ bool LAppDelegate::Initialize()
104      // Cubism3の初期化
105      InitializeCubism();
106  
107 -    SetRootDirectory();
108 -
109      //load model
110      LAppLive2DManager::GetInstance();
111  
112 @@ -214,49 +215,6 @@ void LAppDelegate::InitializeCubism()
113      LAppPal::UpdateTime();
114  }
115  
116 -void LAppDelegate::OnMouseCallBack(GLFWwindow* window, int button, int action, int modify)
117 -{
118 -    if (_view == NULL)
119 -    {
120 -        return;
121 -    }
122 -    if (GLFW_MOUSE_BUTTON_LEFT != button)
123 -    {
124 -        return;
125 -    }
126 -
127 -    if (GLFW_PRESS == action)
128 -    {
129 -        _captured = true;
130 -        _view->OnTouchesBegan(_mouseX, _mouseY);
131 -    }
132 -    else if (GLFW_RELEASE == action)
133 -    {
134 -        if (_captured)
135 -        {
136 -            _captured = false;
137 -            _view->OnTouchesEnded(_mouseX, _mouseY);
138 -        }
139 -    }
140 -}
141 -
142 -void LAppDelegate::OnMouseCallBack(GLFWwindow* window, double x, double y)
143 -{
144 -    _mouseX = static_cast<float>(x);
145 -    _mouseY = static_cast<float>(y);
146 -
147 -    if (!_captured)
148 -    {
149 -        return;
150 -    }
151 -    if (_view == NULL)
152 -    {
153 -        return;
154 -    }
155 -
156 -    _view->OnTouchesMoved(_mouseX, _mouseY);
157 -}
158 -
159  GLuint LAppDelegate::CreateShader()
160  {
161      //バーテックスシェーダのコンパイル
162 @@ -299,29 +257,9 @@ GLuint LAppDelegate::CreateShader()
163      return programId;
164  }
165  
166 -void LAppDelegate::SetRootDirectory()
167 +void LAppDelegate::SetRootDirectory(std::string rootDir)
168  {
169 -    char path[1024];
170 -    ssize_t len = readlink("/proc/self/exe", path, 1024 - 1);
171 -
172 -    if (len != -1)
173 -    {
174 -        path[len] = '\0';
175 -    }
176 -
177 -    std::string pathString(path);
178 -
179 -    pathString = pathString.substr(0, pathString.rfind("Demo"));
180 -    Csm::csmVector<string> splitStrings = this->Split(pathString, '/');
181 -
182 -    this->_rootDirectory = "";
183 -
184 -    for(int i = 0; i < splitStrings.GetSize(); i++)
185 -    {
186 -        this->_rootDirectory = this->_rootDirectory + "/" +splitStrings[i];
187 -    }
188 -
189 -    this->_rootDirectory += "/";
190 +    this->_rootDirectory = rootDir + "/";
191  }
192  
193  Csm::csmVector<string> LAppDelegate::Split(const std::string& baseString, char delimiter)
194 diff -pruN --exclude build ./demo_clean/src/LAppDelegate.hpp ./demo_dev/src/LAppDelegate.hpp
195 --- ./demo_clean/src/LAppDelegate.hpp   2020-10-02 02:01:04.829787750 +0100
196 +++ ./demo_dev/src/LAppDelegate.hpp     2020-10-01 22:47:24.842846271 +0100
197 @@ -40,7 +40,8 @@ public:
198      /**
199      * @brief   APPに必要なものを初期化する。
200      */
201 -    bool Initialize();
202 +    bool Initialize(int initWindowWidth = 0, int initWindowHeight = 0,
203 +                    const char *windowTitle = "SAMPLE");
204  
205      /**
206      * @brief   解放する。
207 @@ -53,25 +54,6 @@ public:
208      void Run();
209  
210      /**
211 -    * @brief   OpenGL用 glfwSetMouseButtonCallback用関数。
212 -    *
213 -    * @param[in]       window            コールバックを呼んだWindow情報
214 -    * @param[in]       button            ボタン種類
215 -    * @param[in]       action            実行結果
216 -    * @param[in]       modify
217 -    */
218 -    void OnMouseCallBack(GLFWwindow* window, int button, int action, int modify);
219 -
220 -    /**
221 -    * @brief   OpenGL用 glfwSetCursorPosCallback用関数。
222 -    *
223 -    * @param[in]       window            コールバックを呼んだWindow情報
224 -    * @param[in]       x                 x座標
225 -    * @param[in]       y                 x座標
226 -    */
227 -    void OnMouseCallBack(GLFWwindow* window, double x, double y);
228 -
229 -    /**
230      * @brief シェーダーを登録する。
231      */
232      GLuint CreateShader();
233 @@ -98,8 +80,10 @@ public:
234  
235      /**
236       * @brief   ルートディレクトリを設定する。
237 +     *
238 +     * @param[in] rootDir : The root directory to set to.
239       */
240 -    void SetRootDirectory();
241 +    void SetRootDirectory(std::string rootDir);
242  
243      /**
244       * @brief   ルートディレクトリを取得する。
245 @@ -146,24 +130,3 @@ private:
246      int _windowWidth;                            ///< Initialize関数で設定したウィンドウ幅
247      int _windowHeight;                           ///< Initialize関数で設定したウィンドウ高さ
248  };
249 -
250 -class EventHandler
251 -{
252 -public:
253 -    /**
254 -    * @brief   glfwSetMouseButtonCallback用コールバック関数。
255 -    */
256 -    static void OnMouseCallBack(GLFWwindow* window, int button, int action, int modify)
257 -    {
258 -        LAppDelegate::GetInstance()->OnMouseCallBack(window, button, action, modify);
259 -    }
260 -
261 -    /**
262 -    * @brief   glfwSetCursorPosCallback用コールバック関数。
263 -    */
264 -    static void OnMouseCallBack(GLFWwindow* window, double x, double y)
265 -    {
266 -         LAppDelegate::GetInstance()->OnMouseCallBack(window, x, y);
267 -    }
268 -
269 -};
270 diff -pruN --exclude build ./demo_clean/src/LAppLive2DManager.cpp ./demo_dev/src/LAppLive2DManager.cpp
271 --- ./demo_clean/src/LAppLive2DManager.cpp      2020-10-02 02:01:04.829787750 +0100
272 +++ ./demo_dev/src/LAppLive2DManager.cpp        2020-10-02 02:00:49.961556700 +0100
273 @@ -52,9 +52,10 @@ void LAppLive2DManager::ReleaseInstance(
274  
275  LAppLive2DManager::LAppLive2DManager()
276      : _viewMatrix(NULL)
277 -    , _sceneIndex(0)
278 +    , _projScaleFactor(1.0f)
279 +    , _translateX(0.0f)
280 +    , _translateY(0.0f)
281  {
282 -    ChangeScene(_sceneIndex);
283  }
284  
285  LAppLive2DManager::~LAppLive2DManager()
286 @@ -98,26 +99,6 @@ void LAppLive2DManager::OnTap(csmFloat32
287      {
288          LAppPal::PrintLog("[APP]tap point: {x:%.2f y:%.2f}", x, y);
289      }
290 -
291 -    for (csmUint32 i = 0; i < _models.GetSize(); i++)
292 -    {
293 -        if (_models[i]->HitTest(HitAreaNameHead, x, y))
294 -        {
295 -            if (DebugLogEnable)
296 -            {
297 -                LAppPal::PrintLog("[APP]hit area: [%s]", HitAreaNameHead);
298 -            }
299 -            _models[i]->SetRandomExpression();
300 -        }
301 -        else if (_models[i]->HitTest(HitAreaNameBody, x, y))
302 -        {
303 -            if (DebugLogEnable)
304 -            {
305 -                LAppPal::PrintLog("[APP]hit area: [%s]", HitAreaNameBody);
306 -            }
307 -            _models[i]->StartRandomMotion(MotionGroupTapBody, PriorityNormal, FinishedMotion);
308 -        }
309 -    }
310  }
311  
312  void LAppLive2DManager::OnUpdate() const
313 @@ -125,7 +106,9 @@ void LAppLive2DManager::OnUpdate() const
314      CubismMatrix44 projection;
315      int width, height;
316      glfwGetWindowSize(LAppDelegate::GetInstance()->GetWindow(), &width, &height);
317 -    projection.Scale(1.0f, static_cast<float>(width) / static_cast<float>(height));
318 +    projection.Scale(_projScaleFactor,
319 +                     _projScaleFactor * static_cast<float>(width) / static_cast<float>(height));
320 +    projection.Translate(_translateX, _translateY);
321  
322      if (_viewMatrix != NULL)
323      {
324 @@ -148,26 +131,10 @@ void LAppLive2DManager::OnUpdate() const
325      }
326  }
327  
328 -void LAppLive2DManager::NextScene()
329 -{
330 -    csmInt32 no = (_sceneIndex + 1) % ModelDirSize;
331 -    ChangeScene(no);
332 -}
333 -
334 -void LAppLive2DManager::ChangeScene(Csm::csmInt32 index)
335 +void LAppLive2DManager::SetModel(std::string modelName)
336  {
337 -    _sceneIndex = index;
338 -    if (DebugLogEnable)
339 -    {
340 -        LAppPal::PrintLog("[APP]model index: %d", _sceneIndex);
341 -    }
342 -
343 -    // ModelDir[]に保持したディレクトリ名から
344 -    // model3.jsonのパスを決定する.
345 -    // ディレクトリ名とmodel3.jsonの名前を一致させておくこと.
346 -    std::string model = ModelDir[index];
347 -    std::string modelPath = LAppDelegate::GetInstance()->GetRootDirectory() + ResourcesPath + model + "/";
348 -    std::string modelJsonName = ModelDir[index];
349 +    std::string modelPath = LAppDelegate::GetInstance()->GetRootDirectory() + ResourcesPath + modelName + "/";
350 +    std::string modelJsonName = modelName;
351      modelJsonName += ".model3.json";
352  
353      ReleaseAllModel();
354 @@ -215,3 +182,20 @@ csmUint32 LAppLive2DManager::GetModelNum
355  {
356      return _models.GetSize();
357  }
358 +
359 +void LAppLive2DManager::SetTracker(MouseCursorTracker *tracker)
360 +{
361 +    for (auto it = _models.Begin(); it != _models.End(); ++it)
362 +    {
363 +        (*it)->SetTracker(tracker);
364 +    }
365 +}
366 +
367 +void LAppLive2DManager::SetProjectionScaleTranslate(float scaleFactor,
368 +                                                    float translateX,
369 +                                                    float translateY)
370 +{
371 +    _projScaleFactor = scaleFactor;
372 +    _translateX = translateX;
373 +    _translateY = translateY;
374 +}
375 diff -pruN --exclude build ./demo_clean/src/LAppLive2DManager.hpp ./demo_dev/src/LAppLive2DManager.hpp
376 --- ./demo_clean/src/LAppLive2DManager.hpp      2020-10-02 02:01:04.825787688 +0100
377 +++ ./demo_dev/src/LAppLive2DManager.hpp        2020-10-01 23:36:24.583055381 +0100
378 @@ -6,12 +6,15 @@
379   */
380  #pragma once
381  
382 +#include <string>
383  #include <CubismFramework.hpp>
384  #include <Math/CubismMatrix44.hpp>
385  #include <Type/csmVector.hpp>
386  
387  class LAppModel;
388  
389 +class MouseCursorTracker;
390 +
391  /**
392  * @brief サンプルアプリケーションにおいてCubismModelを管理するクラス<br>
393  *         モデル生成と破棄、タップイベントの処理、モデル切り替えを行う。
394 @@ -72,16 +75,12 @@ public:
395      void OnUpdate() const;
396  
397      /**
398 -    * @brief   次のシーンに切り替える<br>
399 -    *           サンプルアプリケーションではモデルセットの切り替えを行う。
400 -    */
401 -    void NextScene();
402 -
403 -    /**
404 -    * @brief   シーンを切り替える<br>
405 -    *           サンプルアプリケーションではモデルセットの切り替えを行う。
406 -    */
407 -    void ChangeScene(Csm::csmInt32 index);
408 +     * @brief Set model data
409 +     *
410 +     * @param[in] modelName : Name of model, should be the same for both
411 +     *                        the directory and the model3.json file
412 +     */
413 +    void SetModel(std::string modelName);
414  
415      /**
416       * @brief   モデル個数を得る
417 @@ -89,6 +88,24 @@ public:
418       */
419      Csm::csmUint32 GetModelNum() const;
420  
421 +    /**
422 +     * @brief Set the pointer to the MouseCursorTracker instance
423 +     *
424 +     * @param[in] tracker : Pointer to MouseCursorTracker instance
425 +     */
426 +    void SetTracker(MouseCursorTracker *tracker);
427 +
428 +    /**
429 +     * @brief Set projection scale factor and translation parameters
430 +     *
431 +     * @param[in] scaleFactor : Scale factor applied in both X and Y directions
432 +     * @param[in] translateX : Translation in X direction
433 +     * @param[in] translateY : Translation in Y direction
434 +     */
435 +    void SetProjectionScaleTranslate(float scaleFactor,
436 +                                     float translateX,
437 +                                     float translateY);
438 +
439  private:
440      /**
441      * @brief  コンストラクタ
442 @@ -102,5 +119,8 @@ private:
443  
444      Csm::CubismMatrix44*        _viewMatrix; ///< モデル描画に用いるView行列
445      Csm::csmVector<LAppModel*>  _models; ///< モデルインスタンスのコンテナ
446 -    Csm::csmInt32               _sceneIndex; ///< 表示するシーンのインデックス値
447 +
448 +    float _projScaleFactor;
449 +    float _translateX;
450 +    float _translateY;
451  };
452 diff -pruN --exclude build ./demo_clean/src/LAppModel.cpp ./demo_dev/src/LAppModel.cpp
453 --- ./demo_clean/src/LAppModel.cpp      2020-10-02 02:01:04.825787688 +0100
454 +++ ./demo_dev/src/LAppModel.cpp        2020-10-01 23:34:43.482626010 +0100
455 @@ -21,6 +21,8 @@
456  #include "LAppTextureManager.hpp"
457  #include "LAppDelegate.hpp"
458  
459 +#include "mouse_cursor_tracker.h"
460 +
461  using namespace Live2D::Cubism::Framework;
462  using namespace Live2D::Cubism::Framework::DefaultParameterId;
463  using namespace LAppDefine;
464 @@ -49,6 +51,7 @@ LAppModel::LAppModel()
465      : CubismUserModel()
466      , _modelSetting(NULL)
467      , _userTimeSeconds(0.0f)
468 +    , _tracker(nullptr)
469  {
470      if (DebugLogEnable)
471      {
472 @@ -128,30 +131,6 @@ void LAppModel::SetupModel(ICubismModelS
473          DeleteBuffer(buffer, path.GetRawString());
474      }
475  
476 -    //Expression
477 -    if (_modelSetting->GetExpressionCount() > 0)
478 -    {
479 -        const csmInt32 count = _modelSetting->GetExpressionCount();
480 -        for (csmInt32 i = 0; i < count; i++)
481 -        {
482 -            csmString name = _modelSetting->GetExpressionName(i);
483 -            csmString path = _modelSetting->GetExpressionFileName(i);
484 -            path = _modelHomeDir + path;
485 -
486 -            buffer = CreateBuffer(path.GetRawString(), &size);
487 -            ACubismMotion* motion = LoadExpression(buffer, size, name.GetRawString());
488 -
489 -            if (_expressions[name] != NULL)
490 -            {
491 -                ACubismMotion::Delete(_expressions[name]);
492 -                _expressions[name] = NULL;
493 -            }
494 -            _expressions[name] = motion;
495 -
496 -            DeleteBuffer(buffer, path.GetRawString());
497 -        }
498 -    }
499 -
500      //Physics
501      if (strcmp(_modelSetting->GetPhysicsFileName(), "") != 0)
502      {
503 @@ -335,59 +314,72 @@ void LAppModel::Update()
504      const csmFloat32 deltaTimeSeconds = LAppPal::GetDeltaTime();
505      _userTimeSeconds += deltaTimeSeconds;
506  
507 -    _dragManager->Update(deltaTimeSeconds);
508 -    _dragX = _dragManager->GetX();
509 -    _dragY = _dragManager->GetY();
510 -
511 -    // モーションによるパラメータ更新の有無
512 -    csmBool motionUpdated = false;
513 -
514 -    //-----------------------------------------------------------------
515 -    _model->LoadParameters(); // 前回セーブされた状態をロード
516 -    if (_motionManager->IsFinished())
517 +    if (_tracker)
518      {
519 -        // モーションの再生がない場合、待機モーションの中からランダムで再生する
520 -        StartRandomMotion(MotionGroupIdle, PriorityIdle);
521 -    }
522 -    else
523 -    {
524 -        motionUpdated = _motionManager->UpdateMotion(_model, deltaTimeSeconds); // モーションを更新
525 -    }
526 -    _model->SaveParameters(); // 状態を保存
527 -    //-----------------------------------------------------------------
528 +        auto idMan = CubismFramework::GetIdManager();
529 +        auto params = _tracker->getParams();
530  
531 -    // まばたき
532 -    if (!motionUpdated)
533 -    {
534 -        if (_eyeBlink != NULL)
535 +        // NOTE: Apparently, this LoadParameters/SaveParameters pair
536 +        // is needed for auto breath to work.
537 +        _model->LoadParameters(); // 前回セーブされた状態をロード
538 +        if (_motionManager->IsFinished() && params.randomMotion)
539          {
540 -            // メインモーションの更新がないとき
541 -            _eyeBlink->UpdateParameters(_model, deltaTimeSeconds); // 目パチ
542 +            // モーションの再生がない場合、待機モーションの中からランダムで再生する
543 +            StartRandomMotion(MotionGroupIdle, PriorityIdle);
544          }
545 -    }
546 +        else
547 +        {
548 +            _motionManager->UpdateMotion(_model, deltaTimeSeconds); // モーションを更新
549 +        }
550 +        _model->SaveParameters(); // 状態を保存
551  
552 -    if (_expressionManager != NULL)
553 -    {
554 -        _expressionManager->UpdateMotion(_model, deltaTimeSeconds); // 表情でパラメータ更新(相対変化)
555 -    }
556  
557 -    //ドラッグによる変化
558 -    //ドラッグによる顔の向きの調整
559 -    _model->AddParameterValue(_idParamAngleX, _dragX * 30); // -30から30の値を加える
560 -    _model->AddParameterValue(_idParamAngleY, _dragY * 30);
561 -    _model->AddParameterValue(_idParamAngleZ, _dragX * _dragY * -30);
562 +        if (params.autoBlink && _eyeBlink)
563 +        {
564 +            _eyeBlink->UpdateParameters(_model, deltaTimeSeconds);
565 +        }
566 +        else
567 +        {
568 +            _model->SetParameterValue(idMan->GetId("ParamEyeLOpen"),
569 +                                      params.leftEyeOpenness);
570 +            _model->SetParameterValue(idMan->GetId("ParamEyeROpen"),
571 +                                      params.rightEyeOpenness);
572 +        }
573  
574 -    //ドラッグによる体の向きの調整
575 -    _model->AddParameterValue(_idParamBodyAngleX, _dragX * 10); // -10から10の値を加える
576 +        _model->SetParameterValue(idMan->GetId("ParamMouthForm"),
577 +                                  params.mouthForm);
578  
579 -    //ドラッグによる目の向きの調整
580 -    _model->AddParameterValue(_idParamEyeBallX, _dragX); // -1から1の値を加える
581 -    _model->AddParameterValue(_idParamEyeBallY, _dragY);
582 +        if (params.useLipSync && _lipSync)
583 +        {
584 +            csmFloat32 value = params.lipSyncParam; // 0 to 1
585  
586 -    // 呼吸など
587 -    if (_breath != NULL)
588 -    {
589 -        _breath->UpdateParameters(_model, deltaTimeSeconds);
590 +            for (csmUint32 i = 0; i < _lipSyncIds.GetSize(); ++i)
591 +            {
592 +                _model->AddParameterValue(_lipSyncIds[i], value, 0.8f);
593 +            }
594 +        }
595 +        else
596 +        {
597 +            _model->SetParameterValue(idMan->GetId("ParamMouthOpenY"),
598 +                                      params.mouthOpenness);
599 +        }
600 +
601 +        _model->SetParameterValue(idMan->GetId("ParamEyeLSmile"),
602 +                                  params.leftEyeSmile);
603 +        _model->SetParameterValue(idMan->GetId("ParamEyeRSmile"),
604 +                                  params.rightEyeSmile);
605 +        _model->SetParameterValue(idMan->GetId("ParamAngleX"),
606 +                                  params.faceXAngle);
607 +        _model->SetParameterValue(idMan->GetId("ParamAngleY"),
608 +                                  params.faceYAngle);
609 +        _model->SetParameterValue(idMan->GetId("ParamAngleZ"),
610 +                                  params.faceZAngle);
611 +        if (params.autoBreath && _breath)
612 +        {
613 +            // Note: _model->LoadParameters and SaveParameters is needed
614 +            // before - see above.
615 +            _breath->UpdateParameters(_model, deltaTimeSeconds);
616 +        }
617      }
618  
619      // 物理演算の設定
620 @@ -396,17 +388,6 @@ void LAppModel::Update()
621          _physics->Evaluate(_model, deltaTimeSeconds);
622      }
623  
624 -    // リップシンクの設定
625 -    if (_lipSync)
626 -    {
627 -        csmFloat32 value = 0; // リアルタイムでリップシンクを行う場合、システムから音量を取得して0〜1の範囲で値を入力します。
628 -
629 -        for (csmUint32 i = 0; i < _lipSyncIds.GetSize(); ++i)
630 -        {
631 -            _model->AddParameterValue(_lipSyncIds[i], value, 0.8f);
632 -        }
633 -    }
634 -
635      // ポーズの設定
636      if (_pose != NULL)
637      {
638 @@ -626,3 +607,9 @@ Csm::Rendering::CubismOffscreenFrame_Ope
639  {
640      return _renderBuffer;
641  }
642 +
643 +void LAppModel::SetTracker(MouseCursorTracker *tracker)
644 +{
645 +    _tracker = tracker;
646 +}
647 +
648 diff -pruN --exclude build ./demo_clean/src/LAppModel.hpp ./demo_dev/src/LAppModel.hpp
649 --- ./demo_clean/src/LAppModel.hpp      2020-10-02 02:01:04.829787750 +0100
650 +++ ./demo_dev/src/LAppModel.hpp        2020-10-01 23:35:39.254849094 +0100
651 @@ -13,6 +13,7 @@
652  #include <Type/csmRectF.hpp>
653  #include <Rendering/OpenGL/CubismOffscreenSurface_OpenGLES2.hpp>
654  
655 +#include "mouse_cursor_tracker.h"
656  
657  /**
658   * @brief ユーザーが実際に使用するモデルの実装クラス<br>
659 @@ -113,6 +114,13 @@ public:
660       */
661      Csm::Rendering::CubismOffscreenFrame_OpenGLES2& GetRenderBuffer();
662  
663 +    /**
664 +     * @brief Set the pointer to the MouseCursorTracker instance
665 +     *
666 +     * @param[in] tracker : Pointer to MouseCursorTracker instance
667 +     */
668 +    void SetTracker(MouseCursorTracker *tracker);
669 +
670  protected:
671      /**
672       *  @brief  モデルを描画する処理。モデルを描画する空間のView-Projection行列を渡す。
673 @@ -183,6 +191,8 @@ private:
674      const Csm::CubismId* _idParamEyeBallY; ///< パラメータID: ParamEyeBallXY
675  
676      Csm::Rendering::CubismOffscreenFrame_OpenGLES2 _renderBuffer;   ///< フレームバッファ以外の描画先
677 +
678 +    MouseCursorTracker *_tracker;
679  };
680  
681  
682 diff -pruN --exclude build ./demo_clean/src/LAppPal.cpp ./demo_dev/src/LAppPal.cpp
683 --- ./demo_clean/src/LAppPal.cpp        2020-10-02 02:01:04.829787750 +0100
684 +++ ./demo_dev/src/LAppPal.cpp  2020-10-01 22:47:24.722848453 +0100
685 @@ -6,6 +6,7 @@
686   */
687  
688  #include "LAppPal.hpp"
689 +#include <stdexcept>
690  #include <stdio.h>
691  #include <stdlib.h>
692  #include <stdarg.h>
693 @@ -45,10 +46,7 @@ csmByte* LAppPal::LoadFileAsBytes(const
694      file.open(path, std::ios::in | std::ios::binary);
695      if (!file.is_open())
696      {
697 -        if (DebugLogEnable)
698 -        {
699 -            PrintLog("file open error");
700 -        }
701 +        throw std::runtime_error("Failed to open file " + filePath);
702          return NULL;
703      }
704      file.read(buf, size);
705 diff -pruN --exclude build ./demo_clean/src/LAppTextureManager.cpp ./demo_dev/src/LAppTextureManager.cpp
706 --- ./demo_clean/src/LAppTextureManager.cpp     2020-10-02 02:01:04.833787812 +0100
707 +++ ./demo_dev/src/LAppTextureManager.cpp       2020-10-01 22:47:24.654849690 +0100
708 @@ -96,6 +96,46 @@ LAppTextureManager::TextureInfo* LAppTex
709  
710  }
711  
712 +LAppTextureManager::TextureInfo* LAppTextureManager::CreateTextureFromColor(
713 +    uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha
714 +)
715 +{
716 +    int width = 8, height = 8;
717 +
718 +    uint8_t pixels[height][width][4];
719 +    for (std::size_t h = 0; h < height; h++)
720 +    {
721 +        for (std::size_t w = 0; w < width; w++)
722 +        {
723 +            pixels[h][w][0] = red;
724 +            pixels[h][w][1] = green;
725 +            pixels[h][w][2] = blue;
726 +            pixels[h][w][3] = alpha;
727 +        }
728 +    }
729 +
730 +    GLuint textureId;
731 +    glGenTextures(1, &textureId);
732 +    glBindTexture(GL_TEXTURE_2D, textureId);
733 +    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
734 +
735 +    glGenerateMipmap(GL_TEXTURE_2D);
736 +    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
737 +    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
738 +    glBindTexture(GL_TEXTURE_2D, 0);
739 +
740 +
741 +    LAppTextureManager::TextureInfo* textureInfo = new LAppTextureManager::TextureInfo();
742 +    textureInfo->fileName = "";
743 +    textureInfo->width = width;
744 +    textureInfo->height = height;
745 +    textureInfo->id = textureId;
746 +
747 +    _textures.PushBack(textureInfo);
748 +
749 +    return textureInfo;
750 +}
751 +
752  void LAppTextureManager::ReleaseTextures()
753  {
754      for (Csm::csmUint32 i = 0; i < _textures.GetSize(); i++)
755 diff -pruN --exclude build ./demo_clean/src/LAppTextureManager.hpp ./demo_dev/src/LAppTextureManager.hpp
756 --- ./demo_clean/src/LAppTextureManager.hpp     2020-10-02 02:01:04.825787688 +0100
757 +++ ./demo_dev/src/LAppTextureManager.hpp       2020-10-01 22:47:24.786847290 +0100
758 @@ -72,6 +72,8 @@ public:
759      */
760      TextureInfo* CreateTextureFromPngFile(std::string fileName);
761  
762 +    TextureInfo *CreateTextureFromColor(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha = 255);
763 +
764      /**
765      * @brief 画像の解放
766      *
767 diff -pruN --exclude build ./demo_clean/src/LAppView.cpp ./demo_dev/src/LAppView.cpp
768 --- ./demo_clean/src/LAppView.cpp       2020-10-02 02:01:04.833787812 +0100
769 +++ ./demo_dev/src/LAppView.cpp 2020-10-01 22:47:24.602850636 +0100
770 @@ -13,7 +13,6 @@
771  #include "LAppLive2DManager.hpp"
772  #include "LAppTextureManager.hpp"
773  #include "LAppDefine.hpp"
774 -#include "TouchManager.hpp"
775  #include "LAppSprite.hpp"
776  #include "LAppModel.hpp"
777  
778 @@ -26,8 +25,6 @@ using namespace LAppDefine;
779  LAppView::LAppView():
780      _programId(0),
781      _back(NULL),
782 -    _gear(NULL),
783 -    _power(NULL),
784      _renderSprite(NULL),
785      _renderTarget(SelectTarget_None)
786  {
787 @@ -35,8 +32,6 @@ LAppView::LAppView():
788      _clearColor[1] = 1.0f;
789      _clearColor[2] = 1.0f;
790      _clearColor[3] = 0.0f;
791 -    // タッチ関係のイベント管理
792 -    _touchManager = new TouchManager();
793  
794      // デバイス座標からスクリーン座標に変換するための
795      _deviceToScreen = new CubismMatrix44();
796 @@ -52,10 +47,7 @@ LAppView::~LAppView()
797  
798      delete _viewMatrix;
799      delete _deviceToScreen;
800 -    delete _touchManager;
801      delete _back;
802 -    delete _gear;
803 -    delete _power;
804  }
805  
806  void LAppView::Initialize()
807 @@ -97,9 +89,6 @@ void LAppView::Initialize()
808  void LAppView::Render()
809  {
810      _back->Render();
811 -    _gear->Render();
812 -    _power->Render();
813 -
814  
815      LAppLive2DManager* Live2DManager = LAppLive2DManager::GetInstance();
816  
817 @@ -139,35 +128,17 @@ void LAppView::InitializeSprite()
818      glfwGetWindowSize(LAppDelegate::GetInstance()->GetWindow(), &width, &height);
819  
820      LAppTextureManager* textureManager = LAppDelegate::GetInstance()->GetTextureManager();
821 -    const string resourcesPath = LAppDelegate::GetInstance()->GetRootDirectory() + ResourcesPath;
822  
823 -    string imageName = BackImageName;
824 -    LAppTextureManager::TextureInfo* backgroundTexture = textureManager->CreateTextureFromPngFile(resourcesPath + imageName);
825 +
826 +    LAppTextureManager::TextureInfo* backgroundTexture =
827 +        textureManager->CreateTextureFromColor(0, 255, 0);
828  
829      float x = width * 0.5f;
830      float y = height * 0.5f;
831 -    float fWidth = static_cast<float>(backgroundTexture->width * 2.0f);
832 -    float fHeight = static_cast<float>(height) * 0.95f;
833 +    float fWidth = static_cast<float>(width);
834 +    float fHeight = static_cast<float>(height);
835      _back = new LAppSprite(x, y, fWidth, fHeight, backgroundTexture->id, _programId);
836  
837 -    imageName = GearImageName;
838 -    LAppTextureManager::TextureInfo* gearTexture = textureManager->CreateTextureFromPngFile(resourcesPath + imageName);
839 -
840 -    x = static_cast<float>(width - gearTexture->width * 0.5f);
841 -    y = static_cast<float>(height - gearTexture->height * 0.5f);
842 -    fWidth = static_cast<float>(gearTexture->width);
843 -    fHeight = static_cast<float>(gearTexture->height);
844 -    _gear = new LAppSprite(x, y, fWidth, fHeight, gearTexture->id, _programId);
845 -
846 -    imageName = PowerImageName;
847 -    LAppTextureManager::TextureInfo* powerTexture = textureManager->CreateTextureFromPngFile(resourcesPath + imageName);
848 -
849 -    x = static_cast<float>(width - powerTexture->width * 0.5f);
850 -    y = static_cast<float>(powerTexture->height * 0.5f);
851 -    fWidth = static_cast<float>(powerTexture->width);
852 -    fHeight = static_cast<float>(powerTexture->height);
853 -    _power = new LAppSprite(x, y, fWidth, fHeight, powerTexture->id, _programId);
854 -
855      // 画面全体を覆うサイズ
856      x = width * 0.5f;
857      y = height * 0.5f;
858 @@ -175,52 +146,6 @@ void LAppView::InitializeSprite()
859  
860  }
861  
862 -void LAppView::OnTouchesBegan(float px, float py) const
863 -{
864 -    _touchManager->TouchesBegan(px, py);
865 -}
866 -
867 -void LAppView::OnTouchesMoved(float px, float py) const
868 -{
869 -    float viewX = this->TransformViewX(_touchManager->GetX());
870 -    float viewY = this->TransformViewY(_touchManager->GetY());
871 -
872 -    _touchManager->TouchesMoved(px, py);
873 -
874 -    LAppLive2DManager* Live2DManager = LAppLive2DManager::GetInstance();
875 -    Live2DManager->OnDrag(viewX, viewY);
876 -}
877 -
878 -void LAppView::OnTouchesEnded(float px, float py) const
879 -{
880 -    // タッチ終了
881 -    LAppLive2DManager* live2DManager = LAppLive2DManager::GetInstance();
882 -    live2DManager->OnDrag(0.0f, 0.0f);
883 -    {
884 -
885 -        // シングルタップ
886 -        float x = _deviceToScreen->TransformX(_touchManager->GetX()); // 論理座標変換した座標を取得。
887 -        float y = _deviceToScreen->TransformY(_touchManager->GetY()); // 論理座標変換した座標を取得。
888 -        if (DebugTouchLogEnable)
889 -        {
890 -            LAppPal::PrintLog("[APP]touchesEnded x:%.2f y:%.2f", x, y);
891 -        }
892 -        live2DManager->OnTap(x, y);
893 -
894 -        // 歯車にタップしたか
895 -        if (_gear->IsHit(px, py))
896 -        {
897 -            live2DManager->NextScene();
898 -        }
899 -
900 -        // 電源ボタンにタップしたか
901 -        if (_power->IsHit(px, py))
902 -        {
903 -            LAppDelegate::GetInstance()->AppEnd();
904 -        }
905 -    }
906 -}
907 -
908  float LAppView::TransformViewX(float deviceX) const
909  {
910      float screenX = _deviceToScreen->TransformX(deviceX); // 論理座標変換した座標を取得。
911 @@ -362,32 +287,4 @@ void LAppView::ResizeSprite()
912              _back->ResetRect(x, y, fWidth, fHeight);
913          }
914      }
915 -
916 -    if (_power)
917 -    {
918 -        GLuint id = _power->GetTextureId();
919 -        LAppTextureManager::TextureInfo* texInfo = textureManager->GetTextureInfoById(id);
920 -        if (texInfo)
921 -        {
922 -            x = static_cast<float>(width - texInfo->width * 0.5f);
923 -            y = static_cast<float>(texInfo->height * 0.5f);
924 -            fWidth = static_cast<float>(texInfo->width);
925 -            fHeight = static_cast<float>(texInfo->height);
926 -            _power->ResetRect(x, y, fWidth, fHeight);
927 -        }
928 -    }
929 -
930 -    if (_gear)
931 -    {
932 -        GLuint id = _gear->GetTextureId();
933 -        LAppTextureManager::TextureInfo* texInfo = textureManager->GetTextureInfoById(id);
934 -        if (texInfo)
935 -        {
936 -            x = static_cast<float>(width - texInfo->width * 0.5f);
937 -            y = static_cast<float>(height - texInfo->height * 0.5f);
938 -            fWidth = static_cast<float>(texInfo->width);
939 -            fHeight = static_cast<float>(texInfo->height);
940 -            _gear->ResetRect(x, y, fWidth, fHeight);
941 -        }
942 -    }
943  }
944 diff -pruN --exclude build ./demo_clean/src/LAppView.hpp ./demo_dev/src/LAppView.hpp
945 --- ./demo_clean/src/LAppView.hpp       2020-10-02 02:01:04.825787688 +0100
946 +++ ./demo_dev/src/LAppView.hpp 2020-10-01 22:47:24.802846999 +0100
947 @@ -14,7 +14,6 @@
948  #include "CubismFramework.hpp"
949  #include <Rendering/OpenGL/CubismOffscreenSurface_OpenGLES2.hpp>
950  
951 -class TouchManager;
952  class LAppSprite;
953  class LAppModel;
954  
955 @@ -66,30 +65,6 @@ public:
956      void ResizeSprite();
957  
958      /**
959 -    * @brief タッチされたときに呼ばれる。
960 -    *
961 -    * @param[in]       pointX            スクリーンX座標
962 -    * @param[in]       pointY            スクリーンY座標
963 -    */
964 -    void OnTouchesBegan(float pointX, float pointY) const;
965 -
966 -    /**
967 -    * @brief タッチしているときにポインタが動いたら呼ばれる。
968 -    *
969 -    * @param[in]       pointX            スクリーンX座標
970 -    * @param[in]       pointY            スクリーンY座標
971 -    */
972 -    void OnTouchesMoved(float pointX, float pointY) const;
973 -
974 -    /**
975 -    * @brief タッチが終了したら呼ばれる。
976 -    *
977 -    * @param[in]       pointX            スクリーンX座標
978 -    * @param[in]       pointY            スクリーンY座標
979 -    */
980 -    void OnTouchesEnded(float pointX, float pointY) const;
981 -
982 -    /**
983      * @brief X座標をView座標に変換する。
984      *
985      * @param[in]       deviceX            デバイスX座標
986 @@ -147,13 +122,10 @@ public:
987      void SetRenderTargetClearColor(float r, float g, float b);
988  
989  private:
990 -    TouchManager* _touchManager;                 ///< タッチマネージャー
991      Csm::CubismMatrix44* _deviceToScreen;    ///< デバイスからスクリーンへの行列
992      Csm::CubismViewMatrix* _viewMatrix;      ///< viewMatrix
993      GLuint _programId;                       ///< シェーダID
994      LAppSprite* _back;                       ///< 背景画像
995 -    LAppSprite* _gear;                       ///< ギア画像
996 -    LAppSprite* _power;                      ///< 電源画像
997  
998      // レンダリング先を別ターゲットにする方式の場合に使用
999      LAppSprite* _renderSprite;                                  ///< モードによっては_renderBufferのテクスチャを描画
1000 diff -pruN --exclude build ./demo_clean/src/main.cpp ./demo_dev/src/main.cpp
1001 --- ./demo_clean/src/main.cpp   2020-10-02 02:01:04.825787688 +0100
1002 +++ ./demo_dev/src/main.cpp     2020-10-01 23:42:12.845205308 +0100
1003 @@ -5,18 +5,154 @@
1004   * that can be found at https://www.live2d.com/eula/live2d-open-software-license-agreement_en.html.
1005   */
1006  
1007 +#include <thread>
1008 +#include <stdexcept>
1009 +#include <sstream>
1010 +
1011 +#ifdef __cpp_lib_filesystem
1012 +#include <filesystem>
1013 +namespace fs = std::filesystem;
1014 +#else
1015 +#include <experimental/filesystem>
1016 +namespace fs = std::experimental::filesystem;
1017 +#endif
1018 +
1019  #include "LAppDelegate.hpp"
1020 +#include "LAppLive2DManager.hpp"
1021 +#include "mouse_cursor_tracker.h"
1022 +
1023 +struct CmdArgs
1024 +{
1025 +    int windowWidth;
1026 +    int windowHeight;
1027 +    std::string windowTitle;
1028 +    std::string rootDir;
1029 +    float scaleFactor;
1030 +    float translateX;
1031 +    float translateY;
1032 +    std::string modelName;
1033 +    std::string cfgPath; // Path to config file for MouseCursorTracker
1034 +};
1035 +
1036 +CmdArgs parseArgv(int argc, char *argv[])
1037 +{
1038 +    // I think the command-line args are simple enough to not justify using a library...
1039 +    CmdArgs cmdArgs;
1040 +    // Set default values
1041 +    cmdArgs.windowWidth = 600;
1042 +    cmdArgs.windowHeight = 600;
1043 +    cmdArgs.windowTitle = "MouseTrackerForCubism example";
1044 +    cmdArgs.rootDir = fs::current_path();
1045 +    cmdArgs.scaleFactor = 8.0f;
1046 +    cmdArgs.translateX = 0.0f;
1047 +    cmdArgs.translateY = -2.8f;
1048 +    cmdArgs.modelName = "Haru";
1049 +    cmdArgs.cfgPath = "";
1050 +
1051 +    int i = 1;
1052 +    while (i < argc)
1053 +    {
1054 +        std::string arg = argv[i];
1055 +        std::stringstream ss;
1056 +
1057 +        if (arg == "--window-width" || arg == "-W") // capital W for consistency with height
1058 +        {
1059 +            ss << argv[i + 1];
1060 +            if (!(ss >> cmdArgs.windowWidth))
1061 +            {
1062 +                throw std::runtime_error("Invalid argument for window width");
1063 +            }
1064 +        }
1065 +        else if (arg == "--window-height" || arg == "-H") // avoiding "-h", typically for help
1066 +        {
1067 +            ss << argv[i + 1];
1068 +            if (!(ss >> cmdArgs.windowHeight))
1069 +            {
1070 +                throw std::runtime_error("Invalid argument for window height");
1071 +            }
1072 +        }
1073 +        else if (arg == "--window-title" || arg == "-t")
1074 +        {
1075 +            cmdArgs.windowTitle = argv[i + 1];
1076 +        }
1077 +        else if (arg == "--root-dir" || arg == "-d")
1078 +        {
1079 +            cmdArgs.rootDir = argv[i + 1];
1080 +        }
1081 +        else if (arg == "--scale-factor" || arg == "-f")
1082 +        {
1083 +            ss << argv[i + 1];
1084 +            if (!(ss >> cmdArgs.scaleFactor))
1085 +            {
1086 +                throw std::runtime_error("Invalid argument for scale factor");
1087 +            }
1088 +        }
1089 +        else if (arg == "--translate-x" || arg == "-x")
1090 +        {
1091 +            ss << argv[i + 1];
1092 +            if (!(ss >> cmdArgs.translateX))
1093 +            {
1094 +                throw std::runtime_error("Invalid argument for translate X");
1095 +            }
1096 +        }
1097 +        else if (arg == "--translate-y" || arg == "-y")
1098 +        {
1099 +            ss << argv[i + 1];
1100 +            if (!(ss >> cmdArgs.translateY))
1101 +            {
1102 +                throw std::runtime_error("Invalid argument for translate Y");
1103 +            }
1104 +        }
1105 +        else if (arg == "--model" || arg == "-m")
1106 +        {
1107 +            cmdArgs.modelName = argv[i + 1];
1108 +        }
1109 +        else if (arg == "--config" || arg == "-c")
1110 +        {
1111 +            cmdArgs.cfgPath = argv[i + 1];
1112 +        }
1113 +        else
1114 +        {
1115 +            throw std::runtime_error("Unrecognized argument: " + arg);
1116 +        }
1117 +
1118 +        i += 2;
1119 +    }
1120 +
1121 +    return cmdArgs;
1122 +}
1123  
1124  int main(int argc, char* argv[])
1125  {
1126 -    // create the application instance
1127 -    if (LAppDelegate::GetInstance()->Initialize() == GL_FALSE)
1128 +    auto cmdArgs = parseArgv(argc, argv);
1129 +
1130 +    LAppDelegate *delegate = LAppDelegate::GetInstance();
1131 +
1132 +    if (!delegate->Initialize(cmdArgs.windowWidth,
1133 +                              cmdArgs.windowHeight,
1134 +                              cmdArgs.windowTitle.c_str()))
1135      {
1136 -        return 1;
1137 +        throw std::runtime_error("Unable to initialize LAppDelegate");
1138      }
1139  
1140 -    LAppDelegate::GetInstance()->Run();
1141 +    delegate->SetRootDirectory(cmdArgs.rootDir);
1142 +
1143 +    MouseCursorTracker tracker(cmdArgs.cfgPath);
1144 +
1145 +    std::thread trackerThread(&MouseCursorTracker::mainLoop, &tracker);
1146 +
1147 +    LAppLive2DManager *manager = LAppLive2DManager::GetInstance();
1148 +    manager->SetModel(cmdArgs.modelName);
1149 +
1150 +    manager->SetProjectionScaleTranslate(cmdArgs.scaleFactor,
1151 +                                         cmdArgs.translateX,
1152 +                                         cmdArgs.translateY);
1153 +    manager->SetTracker(&tracker);
1154 +
1155 +    delegate->Run();
1156 +
1157 +    tracker.stop();
1158 +    trackerThread.join();
1159  
1160      return 0;
1161  }
1162 -