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