768e4a45fd2fd9a3407d2a3d5e91851f0a5e5210
[mouse-tracker-for-cubism.git] / example / demo.patch
1 diff --git a/CMakeLists.txt b/CMakeLists.txt
2 index 45c4b1a..a850115 100644
3 --- a/CMakeLists.txt
4 +++ b/CMakeLists.txt
5 @@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.16)
6  # Set app name.
7  set(APP_NAME Demo)
8  # Set directory paths.
9 -set(SDK_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../../../..)
10 +set(SDK_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../CubismSdkForNative-5-r.5)
11  set(CORE_PATH ${SDK_ROOT_PATH}/Core)
12  set(FRAMEWORK_PATH ${SDK_ROOT_PATH}/Framework)
13  set(THIRD_PARTY_PATH ${SDK_ROOT_PATH}/Samples/OpenGL/thirdParty)
14 @@ -35,7 +35,7 @@ set(GLFW_INSTALL OFF CACHE BOOL "" FORCE)
15  set(BUILD_UTILS OFF CACHE BOOL "" FORCE)
16  
17  # Specify version of compiler.
18 -set(CMAKE_CXX_STANDARD 14)
19 +set(CMAKE_CXX_STANDARD 17)
20  set(CMAKE_CXX_STANDARD_REQUIRED ON)
21  set(CMAKE_CXX_EXTENSIONS OFF)
22  
23 @@ -67,6 +67,11 @@ target_link_libraries(Framework Live2DCubismCore glew_s)
24  # Find opengl libraries.
25  find_package(OpenGL REQUIRED)
26  
27 +# Add MouseTrackerForCubism
28 +find_package(PkgConfig)
29 +pkg_check_modules(GTKMM gtkmm-3.0)
30 +add_subdirectory(../.. MouseTrackerForCubism_build)
31 +
32  # Make executable app.
33  add_executable(${APP_NAME})
34  # Add common source files.
35 @@ -79,9 +84,20 @@ target_link_libraries(${APP_NAME}
36    Framework
37    glfw
38    ${OPENGL_LIBRARIES}
39 +  MouseTrackerForCubism
40 +  stdc++fs
41  )
42  # Specify include directories.
43 -target_include_directories(${APP_NAME} PRIVATE ${STB_PATH})
44 +target_include_directories(${APP_NAME} PRIVATE ${STB_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/../../include ${GTKMM_INCLUDE_DIRS})
45 +
46 +# Copy GUI to build directory
47 +add_custom_command(
48 +  TARGET ${APP_NAME}
49 +  POST_BUILD
50 +  COMMAND
51 +    ${CMAKE_COMMAND} -E
52 +      copy ${CMAKE_CURRENT_SOURCE_DIR}/../../src/gui.glade $<TARGET_FILE_DIR:${APP_NAME}>/gui.glade
53 +)
54  
55  # Copy resource directory to build directory.
56  add_custom_command(
57 diff --git a/scripts/make_gcc b/scripts/make_gcc
58 index 4441a91..71adb1a 100755
59 --- a/scripts/make_gcc
60 +++ b/scripts/make_gcc
61 @@ -5,42 +5,9 @@ set -ue
62  SCRIPT_PATH=$(cd $(dirname $0) && pwd)
63  CMAKE_PATH=$SCRIPT_PATH/..
64  BUILD_PATH=$SCRIPT_PATH/../build/make_gcc
65 -MINIMUM_DEMO="OFF"
66 -DATA=""
67 -
68 -if [ "$#" -ne 0 ]; then
69 - DATA="$1"
70 -fi
71 -
72 -while :
73 -do
74 -
75 - if [ -z "$DATA" ]; then
76 -   echo "Choose which format you would like to create the demo."
77 -   echo "Full version : 1"
78 -   echo "Minimum version : 2"
79 -   read -p "Your Choice : " DATA
80 - fi
81 -
82 - case "$DATA" in
83 -   "1" )
84 -     echo "Making Full Demo"
85 -     MINIMUM_DEMO="OFF"
86 -     break ;;
87 -   "2" )
88 -     echo "Making Minimum Demo"
89 -     MINIMUM_DEMO="ON"
90 -     break ;;
91 -   * )
92 -     echo "You need to enter a valid number."
93 -     DATA="" ;;
94 - esac
95 -done
96  
97  # Run CMake.
98  cmake -S "$CMAKE_PATH" \
99    -B "$BUILD_PATH" \
100 -  -D CMAKE_BUILD_TYPE=Release \
101 -  -D CSM_MINIMUM_DEMO=$MINIMUM_DEMO \
102 -  -D GLFW_BUILD_WAYLAND=OFF
103 -cd "$BUILD_PATH" && make
104 +  -D CMAKE_BUILD_TYPE=Release
105 +cd "$BUILD_PATH" && make -j4
106 diff --git a/src/LAppDefine.cpp b/src/LAppDefine.cpp
107 index d7226d2..b534fb7 100644
108 --- a/src/LAppDefine.cpp
109 +++ b/src/LAppDefine.cpp
110 @@ -60,11 +60,11 @@ namespace LAppDefine {
111      const csmInt32 PriorityForce = 3;
112  
113      // デバッグ用ログの表示オプション
114 -    const csmBool DebugLogEnable = true;
115 +    const csmBool DebugLogEnable = false;
116      const csmBool DebugTouchLogEnable = false;
117  
118      // Frameworkから出力するログのレベル設定
119 -    const CubismFramework::Option::LogLevel CubismLoggingLevel = CubismFramework::Option::LogLevel_Verbose;
120 +    const CubismFramework::Option::LogLevel CubismLoggingLevel = CubismFramework::Option::LogLevel_Warning;
121  
122      // デフォルトのレンダーターゲットサイズ
123      const csmInt32 RenderTargetWidth = 1900;
124 diff --git a/src/LAppDelegate.cpp b/src/LAppDelegate.cpp
125 index 242e3ca..2da992d 100644
126 --- a/src/LAppDelegate.cpp
127 +++ b/src/LAppDelegate.cpp
128 @@ -46,7 +46,8 @@ void LAppDelegate::ReleaseInstance()
129      s_instance = NULL;
130  }
131  
132 -bool LAppDelegate::Initialize()
133 +bool LAppDelegate::Initialize(int initWindowWidth, int initWindowHeight,
134 +                              const char *windowTitle)
135  {
136      if (DebugLogEnable)
137      {
138 @@ -64,7 +65,13 @@ bool LAppDelegate::Initialize()
139      }
140  
141      // Windowの生成_
142 -    _window = glfwCreateWindow(RenderTargetWidth, RenderTargetHeight, "SAMPLE", NULL, NULL);
143 +    _window = glfwCreateWindow(
144 +        initWindowWidth ? initWindowWidth : RenderTargetWidth,
145 +        initWindowHeight ? initWindowHeight : RenderTargetHeight,
146 +        windowTitle ? windowTitle : "SAMPLE",
147 +        NULL,
148 +        NULL);
149 +
150      if (_window == NULL)
151      {
152          if (DebugLogEnable)
153 @@ -96,10 +103,6 @@ bool LAppDelegate::Initialize()
154      glEnable(GL_BLEND);
155      glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
156  
157 -    //コールバック関数の登録
158 -    glfwSetMouseButtonCallback(_window, EventHandler::OnMouseCallBack);
159 -    glfwSetCursorPosCallback(_window, EventHandler::OnMouseCallBack);
160 -
161      // ウィンドウサイズ記憶
162      int width, height;
163      glfwGetWindowSize(LAppDelegate::GetInstance()->GetWindow(), &width, &height);
164 diff --git a/src/LAppDelegate.hpp b/src/LAppDelegate.hpp
165 index 89ea99b..50279fd 100644
166 --- a/src/LAppDelegate.hpp
167 +++ b/src/LAppDelegate.hpp
168 @@ -40,7 +40,8 @@ public:
169      /**
170      * @brief   APPに必要なものを初期化する。
171      */
172 -    bool Initialize();
173 +    bool Initialize(int initWindowWidth = 0, int initWindowHeight = 0,
174 +                    const char *windowTitle = "SAMPLE");
175  
176      /**
177      * @brief   解放する。
178 diff --git a/src/LAppLive2DManager.cpp b/src/LAppLive2DManager.cpp
179 index ac3d356..4a5fed6 100644
180 --- a/src/LAppLive2DManager.cpp
181 +++ b/src/LAppLive2DManager.cpp
182 @@ -6,13 +6,7 @@
183   */
184  
185  #include "LAppLive2DManager.hpp"
186 -#include <stdio.h>
187 -#include <stdlib.h>
188 -#include <string.h>
189 -#include <dirent.h>
190 -#include <unistd.h>
191 -#include <libgen.h>
192 -#include <limits.h>
193 +#include <string>
194  #include <GL/glew.h>
195  #include <GLFW/glfw3.h>
196  #include <Rendering/CubismRenderer.hpp>
197 @@ -69,12 +63,11 @@ void LAppLive2DManager::ReleaseInstance()
198  
199  LAppLive2DManager::LAppLive2DManager()
200      : _viewMatrix(NULL)
201 -    , _sceneIndex(0)
202 +    , _projScaleFactor(1.0f)
203 +    , _translateX(0.0f)
204 +    , _translateY(0.0f)
205  {
206      _viewMatrix = new CubismMatrix44();
207 -    SetUpModel();
208 -
209 -    ChangeScene(_sceneIndex);
210  }
211  
212  LAppLive2DManager::~LAppLive2DManager()
213 @@ -94,60 +87,6 @@ void LAppLive2DManager::ReleaseAllModel()
214      _models.Clear();
215  }
216  
217 -void LAppLive2DManager::SetUpModel()
218 -{
219 -    // ResourcesPathの中にあるフォルダ名を全てクロールし、モデルが存在するフォルダを定義する。
220 -    // フォルダはあるが同名の.model3.jsonが見つからなかった場合はリストに含めない。
221 -    struct dirent *dirent;
222 -    csmString crawlPath(LAppDelegate::GetInstance()->GetExecuteAbsolutePath().c_str());
223 -    crawlPath += ResourcesPath;
224 -
225 -    DIR *pDir = opendir(crawlPath.GetRawString());
226 -    if (pDir == NULL) return;
227 -
228 -    _modelDir.Clear();
229 -
230 -    while ((dirent = readdir(pDir)) != NULL)
231 -    {
232 -        if ((dirent->d_type & DT_DIR) && strcmp(dirent->d_name, "..") != 0)
233 -        {
234 -            // フォルダと同名の.model3.jsonがあるか探索する
235 -            struct dirent *dirent2;
236 -
237 -            csmString modelName(dirent->d_name);
238 -
239 -            csmString modelPath(crawlPath);
240 -            modelPath += modelName;
241 -            modelPath.Append(1, '/');
242 -
243 -            csmString model3jsonName(modelName);
244 -            model3jsonName += ".model3.json";
245 -
246 -            DIR *pDir2 = opendir(modelPath.GetRawString());
247 -            while ((dirent2 = readdir(pDir2)) != NULL)
248 -            {
249 -                if (strcmp(dirent2->d_name, model3jsonName.GetRawString()) == 0)
250 -                {
251 -                    _modelDir.PushBack(csmString(dirent->d_name));
252 -                }
253 -            }
254 -            closedir(pDir2);
255 -        }
256 -    }
257 -    closedir(pDir);
258 -    qsort(_modelDir.GetPtr(), _modelDir.GetSize(), sizeof(csmString), CompareCsmString);
259 -}
260 -
261 -csmVector<csmString> LAppLive2DManager::GetModelDir() const
262 -{
263 -    return _modelDir;
264 -}
265 -
266 -csmInt32 LAppLive2DManager::GetModelDirSize() const
267 -{
268 -    return _modelDir.GetSize();
269 -}
270 -
271  LAppModel* LAppLive2DManager::GetModel(csmUint32 no) const
272  {
273      if (no < _models.GetSize())
274 @@ -184,26 +123,6 @@ void LAppLive2DManager::OnTap(csmFloat32 x, csmFloat32 y)
275      {
276          LAppPal::PrintLogLn("[APP]tap point: {x:%.2f y:%.2f}", x, y);
277      }
278 -
279 -    for (csmUint32 i = 0; i < _models.GetSize(); i++)
280 -    {
281 -        if (_models[i]->HitTest(HitAreaNameHead, x, y))
282 -        {
283 -            if (DebugLogEnable)
284 -            {
285 -                LAppPal::PrintLogLn("[APP]hit area: [%s]", HitAreaNameHead);
286 -            }
287 -            _models[i]->SetRandomExpression();
288 -        }
289 -        else if (_models[i]->HitTest(HitAreaNameBody, x, y))
290 -        {
291 -            if (DebugLogEnable)
292 -            {
293 -                LAppPal::PrintLogLn("[APP]hit area: [%s]", HitAreaNameBody);
294 -            }
295 -            _models[i]->StartRandomMotion(MotionGroupTapBody, PriorityNormal, FinishedMotion, BeganMotion);
296 -        }
297 -    }
298  }
299  
300  void LAppLive2DManager::OnUpdate() const
301 @@ -230,12 +149,15 @@ void LAppLive2DManager::OnUpdate() const
302          {
303              // 横に長いモデルを縦長ウィンドウに表示する際モデルの横サイズでscaleを算出する
304              model->GetModelMatrix()->SetWidth(2.0f);
305 -            projection.Scale(1.0f, static_cast<float>(width) / static_cast<float>(height));
306 +            projection.Scale(_projScaleFactor,
307 +                             _projScaleFactor * static_cast<float>(width) / static_cast<float>(height));
308          }
309          else
310          {
311 -            projection.Scale(static_cast<float>(height) / static_cast<float>(width), 1.0f);
312 +            projection.Scale(_projScaleFactor * static_cast<float>(height) / static_cast<float>(width),
313 +                             _projScaleFactor);
314          }
315 +        projection.Translate(_translateX, _translateY);
316  
317          // 必要があればここで乗算
318          if (_viewMatrix != NULL)
319 @@ -257,37 +179,15 @@ void LAppLive2DManager::OnUpdate() const
320      Csm::Rendering::CubismOffscreenManager_OpenGLES2::GetInstance()->ReleaseStaleRenderTextures();
321  }
322  
323 -void LAppLive2DManager::NextScene()
324 +void LAppLive2DManager::SetModel(std::string modelName, bool useOldParamId)
325  {
326 -    csmInt32 no = (_sceneIndex + 1) % GetModelDirSize();
327 -    ChangeScene(no);
328 -}
329 -
330 -void LAppLive2DManager::ChangeScene(Csm::csmInt32 index)
331 -{
332 -    _sceneIndex = index;
333 -    if (DebugLogEnable)
334 -    {
335 -        LAppPal::PrintLogLn("[APP]model index: %d", _sceneIndex);
336 -    }
337 -
338 -    // ModelDir[]に保持したディレクトリ名から
339 -    // model3.jsonのパスを決定する.
340 -    // ディレクトリ名とmodel3.jsonの名前を一致させておくこと.
341 -    const csmString& model = _modelDir[index];
342 -    LAppPal::PrintLogLn("[APP]_modelDir: %s", model.GetRawString());
343 -
344 -    csmString modelPath(LAppDelegate::GetInstance()->GetExecuteAbsolutePath().c_str());
345 -    modelPath += ResourcesPath;
346 -    modelPath += model;
347 -    modelPath.Append(1, '/');
348 -
349 -    csmString modelJsonName(model);
350 +    std::string modelPath = LAppDelegate::GetInstance()->GetExecuteAbsolutePath() + ResourcesPath + modelName + "/";
351 +    std::string modelJsonName = modelName;
352      modelJsonName += ".model3.json";
353  
354      ReleaseAllModel();
355 -    _models.PushBack(new LAppModel());
356 -    _models[0]->LoadAssets(modelPath.GetRawString(), modelJsonName.GetRawString());
357 +    _models.PushBack(new LAppModel(useOldParamId));
358 +    _models[0]->LoadAssets(modelPath.c_str(), modelJsonName.c_str());
359  
360      /*
361       * モデル半透明表示を行うサンプルを提示する。
362 @@ -308,8 +208,8 @@ void LAppLive2DManager::ChangeScene(Csm::csmInt32 index)
363  
364  #if defined(USE_RENDER_TARGET) || defined(USE_MODEL_RENDER_TARGET)
365          // モデル個別にαを付けるサンプルとして、もう1体モデルを作成し、少し位置をずらす
366 -        _models.PushBack(new LAppModel());
367 -        _models[1]->LoadAssets(modelPath.GetRawString(), modelJsonName.GetRawString());
368 +        _models.PushBack(new LAppModel(useOldParamId));
369 +        _models[1]->LoadAssets(modelPath.c_str(), modelJsonName.c_str());
370          _models[1]->GetModelMatrix()->TranslateX(0.2f);
371  #endif
372  
373 @@ -337,3 +237,20 @@ void LAppLive2DManager::SetViewMatrix(CubismMatrix44* m)
374          _viewMatrix->GetArray()[i] = m->GetArray()[i];
375      }
376  }
377 +
378 +void LAppLive2DManager::SetTracker(MouseCursorTracker *tracker)
379 +{
380 +    for (auto it = _models.Begin(); it != _models.End(); ++it)
381 +    {
382 +        (*it)->SetTracker(tracker);
383 +    }
384 +}
385 +
386 +void LAppLive2DManager::SetProjectionScaleTranslate(float scaleFactor,
387 +                                                    float translateX,
388 +                                                    float translateY)
389 +{
390 +    _projScaleFactor = scaleFactor;
391 +    _translateX = translateX;
392 +    _translateY = translateY;
393 +}
394 diff --git a/src/LAppLive2DManager.hpp b/src/LAppLive2DManager.hpp
395 index 2c9939c..5907a82 100644
396 --- a/src/LAppLive2DManager.hpp
397 +++ b/src/LAppLive2DManager.hpp
398 @@ -6,12 +6,15 @@
399   */
400  #pragma once
401  
402 +#include <string>
403  #include <CubismFramework.hpp>
404  #include <Math/CubismMatrix44.hpp>
405  #include <Type/csmVector.hpp>
406  
407  class LAppModel;
408  
409 +class MouseCursorTracker;
410 +
411  /**
412  * @brief サンプルアプリケーションにおいてCubismModelを管理するクラス<br>
413  *         モデル生成と破棄、タップイベントの処理、モデル切り替えを行う。
414 @@ -35,24 +38,6 @@ public:
415      */
416      static void ReleaseInstance();
417  
418 -    /**
419 -    * @brief   Resources フォルダにあるモデルフォルダ名をセットする
420 -    *
421 -    */
422 -    void SetUpModel();
423 -
424 -    /**
425 -    * @brief   Resources フォルダにあるモデルフォルダ名を取得する
426 -    *
427 -    */
428 -    Csm::csmVector<Csm::csmString> GetModelDir() const;
429 -
430 -    /**
431 -    * @brief   Resources フォルダにあるモデルフォルダのサイズを取得する
432 -    *
433 -    */
434 -    Csm::csmInt32 GetModelDirSize() const;
435 -
436      /**
437      * @brief   現在のシーンで保持しているモデルを返す
438      *
439 @@ -98,16 +83,14 @@ public:
440      void OnUpdate() const;
441  
442      /**
443 -    * @brief   次のシーンに切り替える<br>
444 -    *           サンプルアプリケーションではモデルセットの切り替えを行う。
445 -    */
446 -    void NextScene();
447 -
448 -    /**
449 -    * @brief   シーンを切り替える<br>
450 -    *           サンプルアプリケーションではモデルセットの切り替えを行う。
451 -    */
452 -    void ChangeScene(Csm::csmInt32 index);
453 +     * @brief Set model data
454 +     *
455 +     * @param[in] modelName : Name of model, should be the same for both
456 +     *                        the directory and the model3.json file
457 +     * @param[in] useOldParamId : If true, translate new (Cubism 3+)
458 +     *                            parameter IDs to old (Cubism 2.1) ones
459 +     */
460 +    void SetModel(std::string modelName, bool useOldParamId);
461  
462      /**
463       * @brief   モデル個数を得る
464 @@ -120,6 +103,24 @@ public:
465       */
466      void SetViewMatrix(Live2D::Cubism::Framework::CubismMatrix44* m);
467  
468 +    /**
469 +     * @brief Set the pointer to the MouseCursorTracker instance
470 +     *
471 +     * @param[in] tracker : Pointer to MouseCursorTracker instance
472 +     */
473 +    void SetTracker(MouseCursorTracker *tracker);
474 +
475 +    /**
476 +     * @brief Set projection scale factor and translation parameters
477 +     *
478 +     * @param[in] scaleFactor : Scale factor applied in both X and Y directions
479 +     * @param[in] translateX : Translation in X direction
480 +     * @param[in] translateY : Translation in Y direction
481 +     */
482 +    void SetProjectionScaleTranslate(float scaleFactor,
483 +                                     float translateX,
484 +                                     float translateY);
485 +
486  private:
487      /**
488      * @brief  コンストラクタ
489 @@ -133,7 +134,8 @@ private:
490  
491      Csm::CubismMatrix44* _viewMatrix; ///< モデル描画に用いるView行列
492      Csm::csmVector<LAppModel*> _models; ///< モデルインスタンスのコンテナ
493 -    Csm::csmInt32 _sceneIndex; ///< 表示するシーンのインデックス値
494  
495 -    Csm::csmVector<Csm::csmString> _modelDir; ///< モデルディレクトリ名のコンテナ
496 +    float _projScaleFactor;
497 +    float _translateX;
498 +    float _translateY;
499  };
500 diff --git a/src/LAppModel.cpp b/src/LAppModel.cpp
501 index 7b8e0ea..14b9754 100644
502 --- a/src/LAppModel.cpp
503 +++ b/src/LAppModel.cpp
504 @@ -28,27 +28,33 @@
505  #include "Motion/CubismPhysicsUpdater.hpp"
506  #include "Motion/CubismPoseUpdater.hpp"
507  
508 +#include "mouse_cursor_tracker.h"
509 +
510 +#include <iostream>
511 +
512  using namespace Live2D::Cubism::Framework;
513  using namespace Live2D::Cubism::Framework::DefaultParameterId;
514  using namespace LAppDefine;
515  
516 -LAppModel::LAppModel()
517 +LAppModel::LAppModel(bool useOldParamId)
518      : LAppModel_Common()
519      , _modelSetting(NULL)
520      , _userTimeSeconds(0.0f)
521      , _motionUpdated(false)
522 +    , _tracker(nullptr)
523 +    , _useOldParamId(useOldParamId)
524  {
525      if (DebugLogEnable)
526      {
527          _debugMode = true;
528      }
529  
530 -    _idParamAngleX = CubismFramework::GetIdManager()->GetId(ParamAngleX);
531 -    _idParamAngleY = CubismFramework::GetIdManager()->GetId(ParamAngleY);
532 -    _idParamAngleZ = CubismFramework::GetIdManager()->GetId(ParamAngleZ);
533 -    _idParamBodyAngleX = CubismFramework::GetIdManager()->GetId(ParamBodyAngleX);
534 -    _idParamEyeBallX = CubismFramework::GetIdManager()->GetId(ParamEyeBallX);
535 -    _idParamEyeBallY = CubismFramework::GetIdManager()->GetId(ParamEyeBallY);
536 +    _idParamAngleX = CubismFramework::GetIdManager()->GetId(_(ParamAngleX));
537 +    _idParamAngleY = CubismFramework::GetIdManager()->GetId(_(ParamAngleY));
538 +    _idParamAngleZ = CubismFramework::GetIdManager()->GetId(_(ParamAngleZ));
539 +    _idParamBodyAngleX = CubismFramework::GetIdManager()->GetId(_(ParamBodyAngleX));
540 +    _idParamEyeBallX = CubismFramework::GetIdManager()->GetId(_(ParamEyeBallX));
541 +    _idParamEyeBallY = CubismFramework::GetIdManager()->GetId(_(ParamEyeBallY));
542  }
543  
544  LAppModel::~LAppModel()
545 @@ -207,7 +213,7 @@ void LAppModel::SetupModel(ICubismModelSetting* setting)
546          breathParameters.PushBack(CubismBreath::BreathParameterData(_idParamAngleY, 0.0f, 8.0f, 3.5345f, 0.5f));
547          breathParameters.PushBack(CubismBreath::BreathParameterData(_idParamAngleZ, 0.0f, 10.0f, 5.5345f, 0.5f));
548          breathParameters.PushBack(CubismBreath::BreathParameterData(_idParamBodyAngleX, 0.0f, 4.0f, 15.5345f, 0.5f));
549 -        breathParameters.PushBack(CubismBreath::BreathParameterData(CubismFramework::GetIdManager()->GetId(ParamBreath), 0.5f, 0.5f, 3.2345f, 0.5f));
550 +        breathParameters.PushBack(CubismBreath::BreathParameterData(CubismFramework::GetIdManager()->GetId(_(ParamBreath)), 0.5f, 0.5f, 3.2345f, 0.5f));
551  
552          _breath->SetParameters(breathParameters);
553  
554 @@ -241,9 +247,6 @@ void LAppModel::SetupModel(ICubismModelSetting* setting)
555          {
556              _lipSyncIds.PushBack(_modelSetting->GetLipSyncParameterId(i));
557          }
558 -
559 -        CubismLipSyncUpdater* lipSync = CSM_NEW CubismLipSyncUpdater(_lipSyncIds, _wavFileHandler);
560 -        _updateScheduler.AddUpdatableList(lipSync);
561      }
562  
563      // Look
564 @@ -377,27 +380,122 @@ void LAppModel::Update()
565      const csmFloat32 deltaTimeSeconds = LAppPal::GetDeltaTime();
566      _userTimeSeconds += deltaTimeSeconds;
567  
568 -    // モーションによるパラメータ更新の有無
569 -    _motionUpdated = false;
570 -
571 -    //-----------------------------------------------------------------
572 -    _model->LoadParameters(); // 前回セーブされた状態をロード
573 -    if (_motionManager->IsFinished())
574 +    if (_tracker)
575      {
576 -        // モーションの再生がない場合、待機モーションの中からランダムで再生する
577 -        StartRandomMotion(MotionGroupIdle, PriorityIdle);
578 +        auto idMan = CubismFramework::GetIdManager();
579 +        auto params = _tracker->getParams();
580 +
581 +        _model->LoadParameters(); // 前回セーブされた状態をロード
582 +
583 +        int paramsMotionPriority = static_cast<int>(params.motionPriority);
584 +
585 +        if (paramsMotionPriority != PriorityNone)
586 +        {
587 +            StartMotion(params.motionGroup.c_str(), params.motionNumber,
588 +                        paramsMotionPriority);
589 +        }
590 +        else if (params.randomIdleMotion && _motionManager->IsFinished())
591 +        {
592 +            // モーションの再生がない場合、待機モーションの中からランダムで再生する
593 +            StartRandomMotion(MotionGroupIdle, PriorityIdle);
594 +        }
595 +        // FIXME pose does not return to normal after motion
596 +        // if we don't have randomIdleMotion set
597 +        else
598 +        {
599 +            _motionManager->UpdateMotion(_model, deltaTimeSeconds); // モーションを更新
600 +        }
601 +        _model->SaveParameters(); // 状態を保存
602 +
603 +        if (params.expression != "")
604 +        {
605 +            SetExpression(params.expression.c_str());
606 +        }
607 +        if (_expressionManager != NULL)
608 +        {
609 +            _expressionManager->UpdateMotion(_model, deltaTimeSeconds); // 表情でパラメータ更新(相対変化)
610 +        }
611 +
612 +        bool autoBlink = params.autoBlink && _eyeBlink;
613 +        auto eyeLOpenIt = params.live2d.find("ParamEyeLOpen");
614 +        auto eyeROpenIt = params.live2d.find("ParamEyeROpen");
615 +
616 +        if (autoBlink)
617 +        {
618 +            // Handle blink first
619 +            _eyeBlink->UpdateParameters(_model, deltaTimeSeconds);
620 +        }
621 +
622 +        if (eyeLOpenIt != params.live2d.end())
623 +        {
624 +            // If value specified, override blinking
625 +            _model->SetParameterValue(idMan->GetId(_("ParamEyeLOpen")),
626 +                                      eyeLOpenIt->second);
627 +        }
628 +        else if (!autoBlink)
629 +        {
630 +            // If no value specified and no auto blink, set to 1
631 +            _model->SetParameterValue(idMan->GetId(_("ParamEyeLOpen")), 1);
632 +
633 +        }
634 +
635 +        if (eyeROpenIt != params.live2d.end())
636 +        {
637 +            _model->SetParameterValue(idMan->GetId(_("ParamEyeROpen")),
638 +                                      eyeROpenIt->second);
639 +        }
640 +        else if (!autoBlink)
641 +        {
642 +            _model->SetParameterValue(idMan->GetId(_("ParamEyeROpen")), 1);
643 +        }
644 +
645 +
646 +        if (params.useLipSync)
647 +        {
648 +            csmFloat32 value = params.lipSyncParam; // 0 to 1
649 +
650 +            for (csmUint32 i = 0; i < _lipSyncIds.GetSize(); ++i)
651 +            {
652 +                _model->AddParameterValue(_lipSyncIds[i], value, 0.8f);
653 +            }
654 +        }
655 +        else
656 +        {
657 +            _model->SetParameterValue(idMan->GetId(_("ParamMouthOpenY")),
658 +                                      params.live2d["ParamMouthOpenY"]);
659 +        }
660 +
661 +        for (auto const &entry : params.live2d)
662 +        {
663 +            std::string key = entry.first;
664 +            double val = entry.second;
665 +
666 +            if (key != "ParamEyeLOpen" && key != "ParamEyeROpen" &&
667 +                key != "ParamMouthOpenY")
668 +            {
669 +                _model->SetParameterValue(idMan->GetId(_(key)), val);
670 +            }
671 +        }
672 +
673 +        if (params.autoBreath && _breath)
674 +        {
675 +            // Note: _model->LoadParameters and SaveParameters is needed
676 +            // before - see above.
677 +            _breath->UpdateParameters(_model, deltaTimeSeconds);
678 +        }
679      }
680 -    else
681 +
682 +    // 物理演算の設定
683 +    if (_physics != NULL)
684      {
685 -        _motionUpdated = _motionManager->UpdateMotion(_model, deltaTimeSeconds); // モーションを更新
686 +        _physics->Evaluate(_model, deltaTimeSeconds);
687      }
688 -    _model->SaveParameters(); // 状態を保存
689 -    //-----------------------------------------------------------------
690  
691 -    // 不透明度
692 -    _opacity = _model->GetModelOpacity();
693 -
694 -    _updateScheduler.OnLateUpdate(_model, deltaTimeSeconds);
695 +    // ポーズの設定
696 +    if (_pose != NULL)
697 +    {
698 +        _pose->UpdateParameters(_model, deltaTimeSeconds);
699 +    }
700  
701      _model->Update();
702  
703 @@ -455,7 +553,6 @@ CubismMotionQueueEntryHandle LAppModel::StartMotion(const csmChar* group, csmInt
704      {
705          csmString path = voice;
706          path = _modelHomeDir + path;
707 -        _wavFileHandler.Start(path);
708      }
709  
710      if (_debugMode)
711 @@ -607,3 +704,42 @@ Csm::Rendering::CubismRenderTarget_OpenGLES2& LAppModel::GetRenderBuffer()
712  {
713      return _renderBuffer;
714  }
715 +
716 +void LAppModel::SetTracker(MouseCursorTracker *tracker)
717 +{
718 +    _tracker = tracker;
719 +}
720 +
721 +Csm::ICubismModelSetting* LAppModel::GetModelSetting(void) const
722 +{
723 +    return _modelSetting;
724 +}
725 +
726 +Csm::csmString LAppModel::_(std::string s)
727 +{
728 +    std::string ans;
729 +    if (_useOldParamId)
730 +    {
731 +        if (s == "ParamTere")
732 +        {
733 +            ans = "PARAM_CHEEK";
734 +        }
735 +        else
736 +        {
737 +            for (size_t i = 0; i < s.size(); i++)
738 +            {
739 +                if (std::isupper(s[i]) && i != 0)
740 +                {
741 +                    ans += '_';
742 +                }
743 +                ans += std::toupper(s[i]);
744 +            }
745 +        }
746 +    }
747 +    else
748 +    {
749 +        ans = s;
750 +    }
751 +    return csmString(ans.c_str());
752 +}
753 +
754 diff --git a/src/LAppModel.hpp b/src/LAppModel.hpp
755 index 2637a54..1cddb56 100644
756 --- a/src/LAppModel.hpp
757 +++ b/src/LAppModel.hpp
758 @@ -12,8 +12,8 @@
759  #include <Type/csmRectF.hpp>
760  #include <Rendering/OpenGL/CubismRenderTarget_OpenGLES2.hpp>
761  
762 -#include "LAppWavFileHandler_Common.hpp"
763  #include "LAppModel_Common.hpp"
764 +#include "mouse_cursor_tracker.h"
765  
766  /**
767   * @brief ユーザーが実際に使用するモデルの実装クラス<br>
768 @@ -25,8 +25,11 @@ class LAppModel : public LAppModel_Common
769  public:
770      /**
771       * @brief コンストラクタ
772 +     *
773 +     * @param[in] useOldParamId : If true, translate new (Cubism 3+)
774 +     *                            parameter IDs to old (Cubism 2.1)  ones
775       */
776 -    LAppModel();
777 +    LAppModel(bool useOldParamId);
778  
779      /**
780       * @brief デストラクタ
781 @@ -116,6 +119,15 @@ public:
782       */
783      Csm::Rendering::CubismRenderTarget_OpenGLES2& GetRenderBuffer();
784  
785 +    /**
786 +     * @brief Set the pointer to the MouseCursorTracker instance
787 +     *
788 +     * @param[in] tracker : Pointer to MouseCursorTracker instance
789 +     */
790 +    void SetTracker(MouseCursorTracker *tracker);
791 +
792 +    Csm::ICubismModelSetting* GetModelSetting(void) const;
793 +
794  protected:
795      /**
796       *  @brief  モデルを描画する処理。モデルを描画する空間のView-Projection行列を渡す。
797 @@ -169,6 +181,17 @@ private:
798      */
799      void ReleaseExpressions();
800  
801 +    /**
802 +     * @brief Translate new (Cubism 3+) parameter IDs to old (Cubism 2.1) ones
803 +     *
804 +     * @param[in] s : New parameter ID
805 +     *
806 +     * @return Old parameter ID
807 +     */
808 +    Csm::csmString _(std::string s);
809 +
810 +    bool _useOldParamId;
811 +
812      Csm::ICubismModelSetting* _modelSetting; ///< モデルセッティング情報
813      Csm::csmString _modelHomeDir; ///< モデルセッティングが置かれたディレクトリ
814      Csm::csmFloat32 _userTimeSeconds; ///< デルタ時間の積算値[秒]
815 @@ -187,7 +210,7 @@ private:
816  
817      Csm::csmBool _motionUpdated; ///< モーション更新フラグ
818  
819 -    LAppWavFileHandler_Common _wavFileHandler; ///< wavファイルハンドラ
820 +    Csm::Rendering::CubismRenderTarget_OpenGLES2 _renderBuffer;   ///< フレームバッファ以外の描画先    Csm::Rendering::CubismOffscreenSurface_OpenGLES2 _renderBuffer;   ///< フレームバッファ以外の描画先
821  
822 -    Csm::Rendering::CubismRenderTarget_OpenGLES2 _renderBuffer;   ///< フレームバッファ以外の描画先
823 +    MouseCursorTracker *_tracker;
824  };
825 diff --git a/src/LAppTextureManager.cpp b/src/LAppTextureManager.cpp
826 index 97cec74..191bdc0 100644
827 --- a/src/LAppTextureManager.cpp
828 +++ b/src/LAppTextureManager.cpp
829 @@ -96,6 +96,46 @@ LAppTextureManager::TextureInfo* LAppTextureManager::CreateTextureFromPngFile(st
830  
831  }
832  
833 +LAppTextureManager::TextureInfo* LAppTextureManager::CreateTextureFromColor(
834 +    uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha
835 +)
836 +{
837 +    int width = 8, height = 8;
838 +
839 +    uint8_t pixels[height][width][4];
840 +    for (std::size_t h = 0; h < height; h++)
841 +    {
842 +        for (std::size_t w = 0; w < width; w++)
843 +        {
844 +            pixels[h][w][0] = red;
845 +            pixels[h][w][1] = green;
846 +            pixels[h][w][2] = blue;
847 +            pixels[h][w][3] = alpha;
848 +        }
849 +    }
850 +
851 +    GLuint textureId;
852 +    glGenTextures(1, &textureId);
853 +    glBindTexture(GL_TEXTURE_2D, textureId);
854 +    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
855 +
856 +    glGenerateMipmap(GL_TEXTURE_2D);
857 +    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
858 +    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
859 +    glBindTexture(GL_TEXTURE_2D, 0);
860 +
861 +
862 +    LAppTextureManager::TextureInfo* textureInfo = new LAppTextureManager::TextureInfo();
863 +    textureInfo->fileName = "";
864 +    textureInfo->width = width;
865 +    textureInfo->height = height;
866 +    textureInfo->id = textureId;
867 +
868 +    _texturesInfo.PushBack(textureInfo);
869 +
870 +    return textureInfo;
871 +}
872 +
873  void LAppTextureManager::ReleaseTextures()
874  {
875      for (Csm::csmUint32 i = 0; i < _texturesInfo.GetSize(); i++)
876 diff --git a/src/LAppTextureManager.hpp b/src/LAppTextureManager.hpp
877 index a6713df..a42a112 100644
878 --- a/src/LAppTextureManager.hpp
879 +++ b/src/LAppTextureManager.hpp
880 @@ -41,6 +41,8 @@ public:
881      */
882      TextureInfo* CreateTextureFromPngFile(std::string fileName);
883  
884 +    TextureInfo *CreateTextureFromColor(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha = 255);
885 +
886      /**
887      * @brief 画像の解放
888      *
889 diff --git a/src/LAppView.cpp b/src/LAppView.cpp
890 index 4e42040..2ee08db 100644
891 --- a/src/LAppView.cpp
892 +++ b/src/LAppView.cpp
893 @@ -84,9 +84,6 @@ void LAppView::Initialize(int width, int height)
894  void LAppView::Render()
895  {
896      _back->Render();
897 -    _gear->Render();
898 -    _power->Render();
899 -
900  
901      LAppLive2DManager* Live2DManager = LAppLive2DManager::GetInstance();
902  
903 @@ -128,36 +125,17 @@ void LAppView::InitializeSprite()
904      glfwGetWindowSize(LAppDelegate::GetInstance()->GetWindow(), &width, &height);
905  
906      LAppTextureManager* textureManager = LAppDelegate::GetInstance()->GetTextureManager();
907 -    const string resourcesPath = LAppDelegate::GetInstance()->GetExecuteAbsolutePath() + ResourcesPath;
908  
909 -    string imageName = BackImageName;
910 -    LAppTextureManager::TextureInfo* backgroundTexture = textureManager->CreateTextureFromPngFile(resourcesPath + imageName);
911 +
912 +    LAppTextureManager::TextureInfo* backgroundTexture =
913 +        textureManager->CreateTextureFromColor(0, 255, 0);
914  
915      float x = width * 0.5f;
916      float y = height * 0.5f;
917 -    float fHeight = static_cast<float>(height) * 0.95f;
918 -    float ratio = fHeight / static_cast<float>(backgroundTexture->height);
919 -    float fWidth = static_cast<float>(backgroundTexture->width) * ratio;
920 +    float fWidth = static_cast<float>(width);
921 +    float fHeight = static_cast<float>(height);
922      _back = new LAppSprite(x, y, fWidth, fHeight, backgroundTexture->id, programId);
923  
924 -    imageName = GearImageName;
925 -    LAppTextureManager::TextureInfo* gearTexture = textureManager->CreateTextureFromPngFile(resourcesPath + imageName);
926 -
927 -    x = static_cast<float>(width - gearTexture->width * 0.5f);
928 -    y = static_cast<float>(height - gearTexture->height * 0.5f);
929 -    fWidth = static_cast<float>(gearTexture->width);
930 -    fHeight = static_cast<float>(gearTexture->height);
931 -    _gear = new LAppSprite(x, y, fWidth, fHeight, gearTexture->id, programId);
932 -
933 -    imageName = PowerImageName;
934 -    LAppTextureManager::TextureInfo* powerTexture = textureManager->CreateTextureFromPngFile(resourcesPath + imageName);
935 -
936 -    x = static_cast<float>(width - powerTexture->width * 0.5f);
937 -    y = static_cast<float>(powerTexture->height * 0.5f);
938 -    fWidth = static_cast<float>(powerTexture->width);
939 -    fHeight = static_cast<float>(powerTexture->height);
940 -    _power = new LAppSprite(x, y, fWidth, fHeight, powerTexture->id, programId);
941 -
942      // 画面全体を覆うサイズ
943      x = width * 0.5f;
944      y = height * 0.5f;
945 @@ -196,18 +174,6 @@ void LAppView::OnTouchesEnded(float px, float py) const
946              LAppPal::PrintLogLn("[APP]touchesEnded x:%.2f y:%.2f", x, y);
947          }
948          live2DManager->OnTap(x, y);
949 -
950 -        // 歯車にタップしたか
951 -        if (_gear->IsHit(px, py))
952 -        {
953 -            live2DManager->NextScene();
954 -        }
955 -
956 -        // 電源ボタンにタップしたか
957 -        if (_power->IsHit(px, py))
958 -        {
959 -            LAppDelegate::GetInstance()->AppEnd();
960 -        }
961      }
962  }
963  
964 @@ -334,41 +300,6 @@ void LAppView::ResizeSprite()
965              _back->ResetRect(x, y, fWidth, fHeight);
966          }
967      }
968 -
969 -    if (_power)
970 -    {
971 -        GLuint id = _power->GetTextureId();
972 -        LAppTextureManager::TextureInfo* texInfo = textureManager->GetTextureInfoById(id);
973 -        if (texInfo)
974 -        {
975 -            x = static_cast<float>(width - texInfo->width * 0.5f);
976 -            y = static_cast<float>(texInfo->height * 0.5f);
977 -            fWidth = static_cast<float>(texInfo->width);
978 -            fHeight = static_cast<float>(texInfo->height);
979 -            _power->ResetRect(x, y, fWidth, fHeight);
980 -        }
981 -    }
982 -
983 -    if (_gear)
984 -    {
985 -        GLuint id = _gear->GetTextureId();
986 -        LAppTextureManager::TextureInfo* texInfo = textureManager->GetTextureInfoById(id);
987 -        if (texInfo)
988 -        {
989 -            x = static_cast<float>(width - texInfo->width * 0.5f);
990 -            y = static_cast<float>(height - texInfo->height * 0.5f);
991 -            fWidth = static_cast<float>(texInfo->width);
992 -            fHeight = static_cast<float>(texInfo->height);
993 -            _gear->ResetRect(x, y, fWidth, fHeight);
994 -        }
995 -    }
996 -
997 -    if (_renderSprite)
998 -    {
999 -        x = width * 0.5f;
1000 -        y = height * 0.5f;
1001 -        _renderSprite->ResetRect(x, y, static_cast<float>(width), static_cast<float>(height));
1002 -    }
1003  }
1004  
1005  void LAppView::DestroySpriteRenderTarget()
1006 diff --git a/src/main.cpp b/src/main.cpp
1007 index b65c1f0..7da9d0a 100644
1008 --- a/src/main.cpp
1009 +++ b/src/main.cpp
1010 @@ -5,18 +5,186 @@
1011   * that can be found at https://www.live2d.com/eula/live2d-open-software-license-agreement_en.html.
1012   */
1013  
1014 +#include <thread>
1015 +#include <stdexcept>
1016 +#include <sstream>
1017 +#include <vector>
1018 +#include <utility>
1019 +#include <string>
1020 +
1021 +#ifdef __cpp_lib_filesystem
1022 +#include <filesystem>
1023 +namespace fs = std::filesystem;
1024 +#else
1025 +#include <experimental/filesystem>
1026 +namespace fs = std::experimental::filesystem;
1027 +#endif
1028 +
1029 +#include "ICubismModelSetting.hpp"
1030  #include "LAppDelegate.hpp"
1031 +#include "LAppLive2DManager.hpp"
1032 +#include "LAppModel.hpp"
1033 +#include "mouse_cursor_tracker.h"
1034 +
1035 +struct CmdArgs
1036 +{
1037 +    int windowWidth;
1038 +    int windowHeight;
1039 +    std::string windowTitle;
1040 +    std::string rootDir;
1041 +    float scaleFactor;
1042 +    float translateX;
1043 +    float translateY;
1044 +    std::string modelName;
1045 +    bool oldId; // If true, translate new (Cubism 3+) parameter IDs to old (Cubism 2.1) IDs
1046 +    std::string cfgPath; // Path to config file for MouseCursorTracker
1047 +};
1048 +
1049 +CmdArgs parseArgv(int argc, char *argv[])
1050 +{
1051 +    // I think the command-line args are simple enough to not justify using a library...
1052 +    CmdArgs cmdArgs;
1053 +    // Set default values
1054 +    cmdArgs.windowWidth = 600;
1055 +    cmdArgs.windowHeight = 600;
1056 +    cmdArgs.windowTitle = "MouseTrackerForCubism example";
1057 +    cmdArgs.rootDir = fs::current_path();
1058 +    cmdArgs.scaleFactor = 4.5f;
1059 +    cmdArgs.translateX = 0.0f;
1060 +    cmdArgs.translateY = -3.1f;
1061 +    cmdArgs.modelName = "Haru";
1062 +    cmdArgs.oldId = false;
1063 +    cmdArgs.cfgPath = "";
1064 +
1065 +    int i = 1;
1066 +    while (i < argc)
1067 +    {
1068 +        std::string arg = argv[i];
1069 +        std::stringstream ss;
1070 +
1071 +        if (arg == "--window-width" || arg == "-W") // capital W for consistency with height
1072 +        {
1073 +            ss << argv[i + 1];
1074 +            if (!(ss >> cmdArgs.windowWidth))
1075 +            {
1076 +                throw std::runtime_error("Invalid argument for window width");
1077 +            }
1078 +        }
1079 +        else if (arg == "--window-height" || arg == "-H") // avoiding "-h", typically for help
1080 +        {
1081 +            ss << argv[i + 1];
1082 +            if (!(ss >> cmdArgs.windowHeight))
1083 +            {
1084 +                throw std::runtime_error("Invalid argument for window height");
1085 +            }
1086 +        }
1087 +        else if (arg == "--window-title" || arg == "-t")
1088 +        {
1089 +            cmdArgs.windowTitle = argv[i + 1];
1090 +        }
1091 +        else if (arg == "--root-dir" || arg == "-d")
1092 +        {
1093 +            cmdArgs.rootDir = argv[i + 1];
1094 +        }
1095 +        else if (arg == "--scale-factor" || arg == "-f")
1096 +        {
1097 +            ss << argv[i + 1];
1098 +            if (!(ss >> cmdArgs.scaleFactor))
1099 +            {
1100 +                throw std::runtime_error("Invalid argument for scale factor");
1101 +            }
1102 +        }
1103 +        else if (arg == "--translate-x" || arg == "-x")
1104 +        {
1105 +            ss << argv[i + 1];
1106 +            if (!(ss >> cmdArgs.translateX))
1107 +            {
1108 +                throw std::runtime_error("Invalid argument for translate X");
1109 +            }
1110 +        }
1111 +        else if (arg == "--translate-y" || arg == "-y")
1112 +        {
1113 +            ss << argv[i + 1];
1114 +            if (!(ss >> cmdArgs.translateY))
1115 +            {
1116 +                throw std::runtime_error("Invalid argument for translate Y");
1117 +            }
1118 +        }
1119 +        else if (arg == "--model" || arg == "-m")
1120 +        {
1121 +            cmdArgs.modelName = argv[i + 1];
1122 +        }
1123 +        else if (arg == "--config" || arg == "-c")
1124 +        {
1125 +            cmdArgs.cfgPath = argv[i + 1];
1126 +        }
1127 +        else if (arg == "--old-param-id" || arg == "-o")
1128 +        {
1129 +            cmdArgs.oldId = (argv[i + 1][0] == '1');
1130 +        }
1131 +        else
1132 +        {
1133 +            throw std::runtime_error("Unrecognized argument: " + arg);
1134 +        }
1135 +
1136 +        i += 2;
1137 +    }
1138 +
1139 +    return cmdArgs;
1140 +}
1141  
1142  int main(int argc, char* argv[])
1143  {
1144 -    // create the application instance
1145 -    if (LAppDelegate::GetInstance()->Initialize() == GL_FALSE)
1146 +    auto cmdArgs = parseArgv(argc, argv);
1147 +
1148 +    LAppDelegate *delegate = LAppDelegate::GetInstance();
1149 +
1150 +    if (!delegate->Initialize(cmdArgs.windowWidth,
1151 +                              cmdArgs.windowHeight,
1152 +                              cmdArgs.windowTitle.c_str()))
1153      {
1154 -        return 1;
1155 +        throw std::runtime_error("Unable to initialize LAppDelegate");
1156      }
1157  
1158 -    LAppDelegate::GetInstance()->Run();
1159 +    LAppLive2DManager *manager = LAppLive2DManager::GetInstance();
1160 +    manager->SetModel(cmdArgs.modelName, cmdArgs.oldId);
1161 +
1162 +    manager->SetProjectionScaleTranslate(cmdArgs.scaleFactor,
1163 +                                         cmdArgs.translateX,
1164 +                                         cmdArgs.translateY);
1165 +
1166 +    LAppModel *model = manager->GetModel(0);
1167 +    if (!model) throw std::runtime_error("model is null");
1168 +
1169 +    Live2D::Cubism::Framework::ICubismModelSetting *modelSetting = model->GetModelSetting();
1170 +    if (!modelSetting) throw std::runtime_error("modelSetting is null");
1171 +
1172 +    std::vector<std::pair<std::string, int> > motions;
1173 +    int motionGroupCount = modelSetting->GetMotionGroupCount();
1174 +    for (int i = 0; i < motionGroupCount; i++)
1175 +    {
1176 +        const char *motionGroup = modelSetting->GetMotionGroupName(i);
1177 +        int motionCount = modelSetting->GetMotionCount(motionGroup);
1178 +        motions.push_back(std::make_pair(std::string(motionGroup), motionCount));
1179 +    }
1180 +
1181 +    std::vector<std::string> expressions;
1182 +    int expCount = modelSetting->GetExpressionCount();
1183 +    for (int i = 0; i < expCount; i++)
1184 +    {
1185 +        const char *expName = modelSetting->GetExpressionName(i);
1186 +        expressions.push_back(std::string(expName));
1187 +    }
1188 +
1189 +    MouseCursorTracker tracker(cmdArgs.cfgPath, motions, expressions);
1190 +
1191 +    std::thread trackerThread(&MouseCursorTracker::mainLoop, &tracker);
1192 +    manager->SetTracker(&tracker);
1193 +
1194 +    delegate->Run();
1195 +
1196 +    tracker.stop();
1197 +    trackerThread.join();
1198  
1199      return 0;
1200  }
1201 -