1 diff -pruN --exclude build ./demo_clean/CMakeLists.txt ./demo_dev/CMakeLists.txt
2 --- ./demo_clean/CMakeLists.txt 2025-05-29 18:28:25.529155300 +0100
3 +++ ./demo_dev/CMakeLists.txt 2025-05-29 20:27:27.435729700 +0100
4 @@ -9,7 +9,7 @@ option(
8 -set(SDK_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../../../..)
9 +set(SDK_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../CubismSdkForNative-5-r.4)
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 @@ -44,7 +44,7 @@ set(GLFW_INSTALL OFF CACHE BOOL "" FORCE
14 set(BUILD_UTILS OFF CACHE BOOL "" FORCE)
16 # Specify version of compiler.
17 -set(CMAKE_CXX_STANDARD 11)
18 +set(CMAKE_CXX_STANDARD 17)
19 set(CMAKE_CXX_STANDARD_REQUIRED ON)
20 set(CMAKE_CXX_EXTENSIONS OFF)
22 @@ -113,6 +113,9 @@ target_link_libraries(Framework Live2DCu
23 # Find opengl libraries.
24 find_package(OpenGL REQUIRED)
26 +# Add FacialLandmarksForCubism
27 +add_subdirectory(../.. FacialLandmarksForCubism_build)
29 # Make executable app.
30 add_executable(${APP_NAME})
31 # Add common source files.
32 @@ -125,12 +128,14 @@ target_link_libraries(${APP_NAME}
36 + FacialLandmarksForCubism
38 # Solve the MSVCRT confliction.
39 debug -NODEFAULTLIB:libcmtd.lib
40 optimized -NODEFAULTLIB:libcmt.lib
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)
45 # Build in multi-process.
46 target_compile_options(${APP_NAME} PRIVATE /MP)
48 diff -pruN --exclude build ./demo_clean/src/LAppDelegate.cpp ./demo_dev/src/LAppDelegate.cpp
49 --- ./demo_clean/src/LAppDelegate.cpp 2025-05-29 18:28:25.936605800 +0100
50 +++ ./demo_dev/src/LAppDelegate.cpp 2025-05-29 23:48:35.887436800 +0100
51 @@ -43,7 +43,8 @@ void LAppDelegate::ReleaseInstance()
55 -bool LAppDelegate::Initialize()
56 +bool LAppDelegate::Initialize(int initWindowWidth, int initWindowHeight,
57 + const char *windowTitle)
61 @@ -61,7 +62,13 @@ bool LAppDelegate::Initialize()
65 - _window = glfwCreateWindow(RenderTargetWidth, RenderTargetHeight, "SAMPLE", NULL, NULL);
66 + _window = glfwCreateWindow(
67 + initWindowWidth ? initWindowWidth : RenderTargetWidth,
68 + initWindowHeight ? initWindowHeight : RenderTargetHeight,
69 + windowTitle ? windowTitle : "SAMPLE",
76 @@ -93,10 +100,6 @@ bool LAppDelegate::Initialize()
78 glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
81 - glfwSetMouseButtonCallback(_window, EventHandler::OnMouseCallBack);
82 - glfwSetCursorPosCallback(_window, EventHandler::OnMouseCallBack);
86 glfwGetWindowSize(LAppDelegate::GetInstance()->GetWindow(), &width, &height);
87 diff -pruN --exclude build ./demo_clean/src/LAppDelegate.hpp ./demo_dev/src/LAppDelegate.hpp
88 --- ./demo_clean/src/LAppDelegate.hpp 2025-05-29 18:28:26.187813200 +0100
89 +++ ./demo_dev/src/LAppDelegate.hpp 2025-05-29 23:48:48.098223800 +0100
90 @@ -38,7 +38,8 @@ public:
92 * @brief APPに必要なものを初期化する。
95 + bool Initialize(int initWindowWidth = 0, int initWindowHeight = 0,
96 + const char *windowTitle = "SAMPLE");
100 diff -pruN --exclude build ./demo_clean/src/LAppLive2DManager.cpp ./demo_dev/src/LAppLive2DManager.cpp
101 --- ./demo_clean/src/LAppLive2DManager.cpp 2025-05-29 18:28:26.172173900 +0100
102 +++ ./demo_dev/src/LAppLive2DManager.cpp 2025-05-29 23:49:29.615620500 +0100
106 #include "LAppLive2DManager.hpp"
107 -#include <windows.h>
113 #include <GLFW/glfw3.h>
114 #include <Rendering/CubismRenderer.hpp>
116 #include "LAppDelegate.hpp"
117 #include "LAppModel.hpp"
118 #include "LAppView.hpp"
119 +#include "LAppSprite.hpp"
122 using namespace LAppDefine;
123 @@ -65,12 +63,11 @@ void LAppLive2DManager::ReleaseInstance(
125 LAppLive2DManager::LAppLive2DManager()
128 + , _projScaleFactor(1.0f)
129 + , _translateX(0.0f)
130 + , _translateY(0.0f)
132 _viewMatrix = new CubismMatrix44();
135 - ChangeScene(_sceneIndex);
138 LAppLive2DManager::~LAppLive2DManager()
139 @@ -89,63 +86,6 @@ void LAppLive2DManager::ReleaseAllModel(
143 -void LAppLive2DManager::SetUpModel()
145 - // ResourcesPathの中にあるフォルダ名を全てクロールし、モデルが存在するフォルダを定義する。
146 - // フォルダはあるが同名の.model3.jsonが見つからなかった場合はリストに含めない。
147 - // 一部文字が受け取れないためワイド文字で受け取ってUTF8に変換し格納する。
149 - csmString crawlPath(ResourcesPath);
150 - crawlPath += "*.*";
152 - wchar_t wideStr[MAX_PATH];
153 - csmChar name[MAX_PATH];
154 - LAppPal::ConvertMultiByteToWide(crawlPath.GetRawString(), wideStr, MAX_PATH);
156 - struct _wfinddata_t fdata;
157 - intptr_t fh = _wfindfirst(wideStr, &fdata);
165 - while (_wfindnext(fh, &fdata) == 0)
167 - if ((fdata.attrib & _A_SUBDIR) && wcscmp(fdata.name, L"..") != 0)
169 - LAppPal::ConvertWideToMultiByte(fdata.name, name, MAX_PATH);
171 - // フォルダと同名の.model3.jsonがあるか探索する
172 - csmString model3jsonPath(ResourcesPath);
173 - model3jsonPath += name;
174 - model3jsonPath.Append(1, '/');
175 - model3jsonPath += name;
176 - model3jsonPath += ".model3.json";
178 - LAppPal::ConvertMultiByteToWide(model3jsonPath.GetRawString(), wideStr, MAX_PATH);
180 - struct _wfinddata_t fdata2;
181 - if (_wfindfirst(wideStr, &fdata2) != -1)
183 - _modelDir.PushBack(csmString(name));
187 - qsort(_modelDir.GetPtr(), _modelDir.GetSize(), sizeof(csmString), CompareCsmString);
190 -csmVector<csmString> LAppLive2DManager::GetModelDir() const
195 -csmInt32 LAppLive2DManager::GetModelDirSize() const
197 - return _modelDir.GetSize();
200 LAppModel* LAppLive2DManager::GetModel(csmUint32 no) const
202 if (no < _models.GetSize())
203 @@ -172,26 +112,6 @@ void LAppLive2DManager::OnTap(csmFloat32
205 LAppPal::PrintLogLn("[APP]tap point: {x:%.2f y:%.2f}", x, y);
208 - for (csmUint32 i = 0; i < _models.GetSize(); i++)
210 - if (_models[i]->HitTest(HitAreaNameHead, x, y))
212 - if (DebugLogEnable)
214 - LAppPal::PrintLogLn("[APP]hit area: [%s]", HitAreaNameHead);
216 - _models[i]->SetRandomExpression();
218 - else if (_models[i]->HitTest(HitAreaNameBody, x, y))
220 - if (DebugLogEnable)
222 - LAppPal::PrintLogLn("[APP]hit area: [%s]", HitAreaNameBody);
224 - _models[i]->StartRandomMotion(MotionGroupTapBody, PriorityNormal, FinishedMotion, BeganMotion);
229 void LAppLive2DManager::OnUpdate() const
230 @@ -215,12 +135,15 @@ void LAppLive2DManager::OnUpdate() const
232 // 横に長いモデルを縦長ウィンドウに表示する際モデルの横サイズでscaleを算出する
233 model->GetModelMatrix()->SetWidth(2.0f);
234 - projection.Scale(1.0f, static_cast<float>(width) / static_cast<float>(height));
235 + projection.Scale(_projScaleFactor,
236 + _projScaleFactor * static_cast<float>(width) / static_cast<float>(height));
240 - projection.Scale(static_cast<float>(height) / static_cast<float>(width), 1.0f);
241 + projection.Scale(_projScaleFactor * static_cast<float>(height) / static_cast<float>(width),
244 + projection.Translate(_translateX, _translateY);
247 if (_viewMatrix != NULL)
248 @@ -239,34 +162,15 @@ void LAppLive2DManager::OnUpdate() const
252 -void LAppLive2DManager::NextScene()
253 +void LAppLive2DManager::SetModel(std::string modelName, bool useOldParamId)
255 - csmInt32 no = (_sceneIndex + 1) % GetModelDirSize();
259 -void LAppLive2DManager::ChangeScene(Csm::csmInt32 index)
261 - _sceneIndex = index;
262 - if (DebugLogEnable)
264 - LAppPal::PrintLogLn("[APP]model index: %d", _sceneIndex);
267 - // model3.jsonのパスを決定する.
268 - // ディレクトリ名とmodel3.jsonの名前を一致していることが条件
269 - const csmString& model = _modelDir[index];
271 - csmString modelPath(ResourcesPath);
272 - modelPath += model;
273 - modelPath.Append(1, '/');
275 - csmString modelJsonName(model);
276 + std::string modelPath = ResourcesPath + modelName + "/";
277 + std::string modelJsonName = modelName;
278 modelJsonName += ".model3.json";
281 - _models.PushBack(new LAppModel());
282 - _models[0]->LoadAssets(modelPath.GetRawString(), modelJsonName.GetRawString());
283 + _models.PushBack(new LAppModel(useOldParamId));
284 + _models[0]->LoadAssets(modelPath.c_str(), modelJsonName.c_str());
287 * モデル半透明表示を行うサンプルを提示する。
288 @@ -287,8 +191,8 @@ void LAppLive2DManager::ChangeScene(Csm:
290 #if defined(USE_RENDER_TARGET) || defined(USE_MODEL_RENDER_TARGET)
291 // モデル個別にαを付けるサンプルとして、もう1体モデルを作成し、少し位置をずらす
292 - _models.PushBack(new LAppModel());
293 - _models[1]->LoadAssets(modelPath.GetRawString(), modelJsonName.GetRawString());
294 + _models.PushBack(new LAppModel(useOldParamId));
295 + _models[1]->LoadAssets(modelPath.c_str(), modelJsonName.c_str());
296 _models[1]->GetModelMatrix()->TranslateX(0.2f);
299 @@ -311,3 +215,20 @@ void LAppLive2DManager::SetViewMatrix(Cu
300 _viewMatrix->GetArray()[i] = m->GetArray()[i];
304 +void LAppLive2DManager::SetFacialLandmarkDetector(FacialLandmarkDetector *detector)
306 + for (auto it = _models.Begin(); it != _models.End(); ++it)
308 + (*it)->SetFacialLandmarkDetector(detector);
312 +void LAppLive2DManager::SetProjectionScaleTranslate(float scaleFactor,
316 + _projScaleFactor = scaleFactor;
317 + _translateX = translateX;
318 + _translateY = translateY;
320 diff -pruN --exclude build ./demo_clean/src/LAppLive2DManager.hpp ./demo_dev/src/LAppLive2DManager.hpp
321 --- ./demo_clean/src/LAppLive2DManager.hpp 2025-05-29 18:28:26.454266400 +0100
322 +++ ./demo_dev/src/LAppLive2DManager.hpp 2025-05-29 23:49:37.447547800 +0100
328 #include <CubismFramework.hpp>
329 #include <Math/CubismMatrix44.hpp>
330 #include <Type/csmVector.hpp>
334 +class FacialLandmarkDetector;
337 * @brief サンプルアプリケーションにおいてCubismModelを管理するクラス<br>
338 * モデル生成と破棄、タップイベントの処理、モデル切り替えを行う。
339 @@ -37,24 +40,6 @@ public:
340 static void ReleaseInstance();
343 - * @brief Resources フォルダにあるモデルフォルダ名をセットする
349 - * @brief Resources フォルダにあるモデルフォルダ名を取得する
352 - Csm::csmVector<Csm::csmString> GetModelDir() const;
355 - * @brief Resources フォルダにあるモデルフォルダのサイズを取得する
358 - Csm::csmInt32 GetModelDirSize() const;
361 * @brief 現在のシーンで保持しているモデルを返す
363 * @param[in] no モデルリストのインデックス値
364 @@ -91,16 +76,14 @@ public:
365 void OnUpdate() const;
368 - * @brief 次のシーンに切り替える<br>
369 - * サンプルアプリケーションではモデルセットの切り替えを行う。
374 - * @brief シーンを切り替える<br>
375 - * サンプルアプリケーションではモデルセットの切り替えを行う。
377 - void ChangeScene(Csm::csmInt32 index);
378 + * @brief Set model data
380 + * @param[in] modelName : Name of model, should be the same for both
381 + * the directory and the model3.json file
382 + * @param[in] useOldParamId : If true, translate new (Cubism 3+)
383 + * parameter IDs to old (Cubism 2.1) ones
385 + void SetModel(std::string modelName, bool useOldParamId);
389 @@ -113,6 +96,24 @@ public:
391 void SetViewMatrix(Live2D::Cubism::Framework::CubismMatrix44* m);
394 + * @brief Set the pointer to the FacialLandmarkDetector instance
396 + * @param[in] detector : Pointer to FacialLandmarkDetector instance
398 + void SetFacialLandmarkDetector(FacialLandmarkDetector *detector);
401 + * @brief Set projection scale factor and translation parameters
403 + * @param[in] scaleFactor : Scale factor applied in both X and Y directions
404 + * @param[in] translateX : Translation in X direction
405 + * @param[in] translateY : Translation in Y direction
407 + void SetProjectionScaleTranslate(float scaleFactor,
414 @@ -126,7 +127,8 @@ private:
416 Csm::CubismMatrix44* _viewMatrix; ///< モデル描画に用いるView行列
417 Csm::csmVector<LAppModel*> _models; ///< モデルインスタンスのコンテナ
418 - Csm::csmInt32 _sceneIndex; ///< 表示するシーンのインデックス値
420 - Csm::csmVector<Csm::csmString> _modelDir; ///< モデルディレクトリ名のコンテナ
421 + float _projScaleFactor;
425 diff -pruN --exclude build ./demo_clean/src/LAppModel.cpp ./demo_dev/src/LAppModel.cpp
426 --- ./demo_clean/src/LAppModel.cpp 2025-05-29 18:28:26.423050700 +0100
427 +++ ./demo_dev/src/LAppModel.cpp 2025-05-29 23:50:40.648300100 +0100
429 #include "LAppTextureManager.hpp"
430 #include "LAppDelegate.hpp"
432 +#include "facial_landmark_detector.h"
434 using namespace Live2D::Cubism::Framework;
435 using namespace Live2D::Cubism::Framework::DefaultParameterId;
436 using namespace LAppDefine;
438 -LAppModel::LAppModel()
439 +LAppModel::LAppModel(bool useOldParamId)
441 , _modelSetting(NULL)
442 , _userTimeSeconds(0.0f)
443 + , _detector(nullptr)
444 + , _useOldParamId(useOldParamId)
446 if (MocConsistencyValidationEnable)
448 @@ -44,12 +48,12 @@ LAppModel::LAppModel()
452 - _idParamAngleX = CubismFramework::GetIdManager()->GetId(ParamAngleX);
453 - _idParamAngleY = CubismFramework::GetIdManager()->GetId(ParamAngleY);
454 - _idParamAngleZ = CubismFramework::GetIdManager()->GetId(ParamAngleZ);
455 - _idParamBodyAngleX = CubismFramework::GetIdManager()->GetId(ParamBodyAngleX);
456 - _idParamEyeBallX = CubismFramework::GetIdManager()->GetId(ParamEyeBallX);
457 - _idParamEyeBallY = CubismFramework::GetIdManager()->GetId(ParamEyeBallY);
458 + _idParamAngleX = CubismFramework::GetIdManager()->GetId(_(ParamAngleX));
459 + _idParamAngleY = CubismFramework::GetIdManager()->GetId(_(ParamAngleY));
460 + _idParamAngleZ = CubismFramework::GetIdManager()->GetId(_(ParamAngleZ));
461 + _idParamBodyAngleX = CubismFramework::GetIdManager()->GetId(_(ParamBodyAngleX));
462 + _idParamEyeBallX = CubismFramework::GetIdManager()->GetId(_(ParamEyeBallX));
463 + _idParamEyeBallY = CubismFramework::GetIdManager()->GetId(_(ParamEyeBallY));
466 LAppModel::~LAppModel()
467 @@ -122,33 +126,6 @@ void LAppModel::SetupModel(ICubismModelS
468 DeleteBuffer(buffer, path.GetRawString());
472 - if (_modelSetting->GetExpressionCount() > 0)
474 - const csmInt32 count = _modelSetting->GetExpressionCount();
475 - for (csmInt32 i = 0; i < count; i++)
477 - csmString name = _modelSetting->GetExpressionName(i);
478 - csmString path = _modelSetting->GetExpressionFileName(i);
479 - path = _modelHomeDir + path;
481 - buffer = CreateBuffer(path.GetRawString(), &size);
482 - ACubismMotion* motion = LoadExpression(buffer, size, name.GetRawString());
486 - if (_expressions[name] != NULL)
488 - ACubismMotion::Delete(_expressions[name]);
489 - _expressions[name] = NULL;
491 - _expressions[name] = motion;
494 - DeleteBuffer(buffer, path.GetRawString());
499 if (strcmp(_modelSetting->GetPhysicsFileName(), "") != 0)
501 @@ -187,7 +164,7 @@ void LAppModel::SetupModel(ICubismModelS
502 breathParameters.PushBack(CubismBreath::BreathParameterData(_idParamAngleY, 0.0f, 8.0f, 3.5345f, 0.5f));
503 breathParameters.PushBack(CubismBreath::BreathParameterData(_idParamAngleZ, 0.0f, 10.0f, 5.5345f, 0.5f));
504 breathParameters.PushBack(CubismBreath::BreathParameterData(_idParamBodyAngleX, 0.0f, 4.0f, 15.5345f, 0.5f));
505 - breathParameters.PushBack(CubismBreath::BreathParameterData(CubismFramework::GetIdManager()->GetId(ParamBreath), 0.5f, 0.5f, 3.2345f, 0.5f));
506 + breathParameters.PushBack(CubismBreath::BreathParameterData(CubismFramework::GetIdManager()->GetId(_(ParamBreath)), 0.5f, 0.5f, 3.2345f, 0.5f));
508 _breath->SetParameters(breathParameters);
510 @@ -211,21 +188,6 @@ void LAppModel::SetupModel(ICubismModelS
516 - csmInt32 lipSyncIdCount = _modelSetting->GetLipSyncParameterCount();
517 - for (csmInt32 i = 0; i < lipSyncIdCount; ++i)
519 - _lipSyncIds.PushBack(_modelSetting->GetLipSyncParameterId(i));
523 - if (_modelSetting == NULL || _modelMatrix == NULL)
525 - LAppPal::PrintLogLn("Failed to SetupModel().");
530 csmMap<csmString, csmFloat32> layout;
531 _modelSetting->GetLayoutMap(layout);
532 @@ -330,62 +292,57 @@ void LAppModel::Update()
533 const csmFloat32 deltaTimeSeconds = LAppPal::GetDeltaTime();
534 _userTimeSeconds += deltaTimeSeconds;
536 - _dragManager->Update(deltaTimeSeconds);
537 - _dragX = _dragManager->GetX();
538 - _dragY = _dragManager->GetY();
540 - // モーションによるパラメータ更新の有無
541 - csmBool motionUpdated = false;
543 - //-----------------------------------------------------------------
544 - _model->LoadParameters(); // 前回セーブされた状態をロード
545 - if (_motionManager->IsFinished())
548 - // モーションの再生がない場合、待機モーションの中からランダムで再生する
549 - StartRandomMotion(MotionGroupIdle, PriorityIdle);
553 - motionUpdated = _motionManager->UpdateMotion(_model, deltaTimeSeconds); // モーションを更新
555 - _model->SaveParameters(); // 状態を保存
556 - //-----------------------------------------------------------------
557 + auto idMan = CubismFramework::GetIdManager();
558 + auto params = _detector->getParams();
561 - _opacity = _model->GetModelOpacity();
564 - if (!motionUpdated)
566 - if (_eyeBlink != NULL)
567 + // NOTE: Apparently, this LoadParameters/SaveParameters pair
568 + // is needed for auto breath to work.
569 + _model->LoadParameters(); // 前回セーブされた状態をロード
570 + if (_motionManager->IsFinished() && params.randomMotion)
572 - // メインモーションの更新がないとき
573 - _eyeBlink->UpdateParameters(_model, deltaTimeSeconds); // 目パチ
574 + // モーションの再生がない場合、待機モーションの中からランダムで再生する
575 + StartRandomMotion(MotionGroupIdle, PriorityIdle);
579 - if (_expressionManager != NULL)
581 - _expressionManager->UpdateMotion(_model, deltaTimeSeconds); // 表情でパラメータ更新(相対変化)
586 - _model->AddParameterValue(_idParamAngleX, _dragX * 30); // -30から30の値を加える
587 - _model->AddParameterValue(_idParamAngleY, _dragY * 30);
588 - _model->AddParameterValue(_idParamAngleZ, _dragX * _dragY * -30);
591 - _model->AddParameterValue(_idParamBodyAngleX, _dragX * 10); // -10から10の値を加える
594 + _motionManager->UpdateMotion(_model, deltaTimeSeconds); // モーションを更新
596 + _model->SaveParameters(); // 状態を保存
599 - _model->AddParameterValue(_idParamEyeBallX, _dragX); // -1から1の値を加える
600 - _model->AddParameterValue(_idParamEyeBallY, _dragY);
603 - if (_breath != NULL)
605 - _breath->UpdateParameters(_model, deltaTimeSeconds);
606 + if (params.autoBlink && _eyeBlink)
608 + _eyeBlink->UpdateParameters(_model, deltaTimeSeconds);
612 + _model->SetParameterValue(idMan->GetId(_("ParamEyeLOpen")),
613 + params.leftEyeOpenness);
614 + _model->SetParameterValue(idMan->GetId(_("ParamEyeROpen")),
615 + params.rightEyeOpenness);
617 + _model->SetParameterValue(idMan->GetId(_("ParamMouthForm")),
619 + _model->SetParameterValue(idMan->GetId(_("ParamMouthOpenY")),
620 + params.mouthOpenness);
621 + _model->SetParameterValue(idMan->GetId(_("ParamEyeLSmile")),
622 + params.leftEyeSmile);
623 + _model->SetParameterValue(idMan->GetId(_("ParamEyeRSmile")),
624 + params.rightEyeSmile);
625 + _model->SetParameterValue(idMan->GetId(_("ParamAngleX")),
626 + params.faceXAngle);
627 + _model->SetParameterValue(idMan->GetId(_("ParamAngleY")),
628 + params.faceYAngle);
629 + _model->SetParameterValue(idMan->GetId(_("ParamAngleZ")),
630 + params.faceZAngle);
631 + if (params.autoBreath && _breath)
633 + // Note: _model->LoadParameters and SaveParameters is needed
634 + // before - see above.
635 + _breath->UpdateParameters(_model, deltaTimeSeconds);
640 @@ -394,22 +351,6 @@ void LAppModel::Update()
641 _physics->Evaluate(_model, deltaTimeSeconds);
647 - // リアルタイムでリップシンクを行う場合、システムから音量を取得して0〜1の範囲で値を入力します。
648 - csmFloat32 value = 0.0f;
651 - _wavFileHandler.Update(deltaTimeSeconds);
652 - value = _wavFileHandler.GetRms();
654 - for (csmUint32 i = 0; i < _lipSyncIds.GetSize(); ++i)
656 - _model->AddParameterValue(_lipSyncIds[i], value, 0.8f);
663 @@ -480,7 +421,6 @@ CubismMotionQueueEntryHandle LAppModel::
665 csmString path = voice;
666 path = _modelHomeDir + path;
667 - _wavFileHandler.Start(path);
671 @@ -659,3 +599,37 @@ csmBool LAppModel::HasMocConsistencyFrom
676 +void LAppModel::SetFacialLandmarkDetector(FacialLandmarkDetector *detector)
678 + _detector = detector;
681 +Csm::csmString LAppModel::_(std::string s)
684 + if (_useOldParamId)
686 + if (s == "ParamTere")
688 + ans = "PARAM_CHEEK";
692 + for (size_t i = 0; i < s.size(); i++)
694 + if (std::isupper(s[i]) && i != 0)
698 + ans += std::toupper(s[i]);
706 + return csmString(ans.c_str());
709 diff -pruN --exclude build ./demo_clean/src/LAppModel.hpp ./demo_dev/src/LAppModel.hpp
710 --- ./demo_clean/src/LAppModel.hpp 2025-05-29 18:28:26.391768300 +0100
711 +++ ./demo_dev/src/LAppModel.hpp 2025-05-29 23:50:49.650320100 +0100
713 #include <Type/csmRectF.hpp>
714 #include <Rendering/OpenGL/CubismOffscreenSurface_OpenGLES2.hpp>
716 -#include "LAppWavFileHandler_Common.hpp"
717 #include "LAppModel_Common.hpp"
718 +#include "facial_landmark_detector.h"
721 * @brief ユーザーが実際に使用するモデルの実装クラス<br>
722 @@ -25,8 +25,11 @@ class LAppModel : public LAppModel_Commo
727 + * @param[in] useOldParamId : If true, translate new (Cubism 3+)
728 + * parameter IDs to old (Cubism 2.1) ones
731 + LAppModel(bool useOldParamId);
735 @@ -124,6 +127,13 @@ public:
737 Csm::csmBool HasMocConsistencyFromFile(const Csm::csmChar* mocFileName);
740 + * @brief Set the pointer to the FacialLandmarkDetector instance
742 + * @param[in] detector : Pointer to FacialLandmarkDetector instance
744 + void SetFacialLandmarkDetector(FacialLandmarkDetector *detector);
748 * @brief モデルを描画する処理。モデルを描画する空間のView-Projection行列を渡す。
749 @@ -177,6 +187,17 @@ private:
751 void ReleaseExpressions();
754 + * @brief Translate new (Cubism 3+) parameter IDs to old (Cubism 2.1) ones
756 + * @param[in] s : New parameter ID
758 + * @return Old parameter ID
760 + Csm::csmString _(std::string s);
762 + bool _useOldParamId;
764 Csm::ICubismModelSetting* _modelSetting; ///< モデルセッティング情報
765 Csm::csmString _modelHomeDir; ///< モデルセッティングが置かれたディレクトリ
766 Csm::csmFloat32 _userTimeSeconds; ///< デルタ時間の積算値[秒]
767 @@ -193,7 +214,7 @@ private:
768 const Csm::CubismId* _idParamEyeBallX; ///< パラメータID: ParamEyeBallX
769 const Csm::CubismId* _idParamEyeBallY; ///< パラメータID: ParamEyeBallXY
771 - LAppWavFileHandler_Common _wavFileHandler; ///< wavファイルハンドラ
773 Csm::Rendering::CubismOffscreenSurface_OpenGLES2 _renderBuffer; ///< フレームバッファ以外の描画先
775 + FacialLandmarkDetector *_detector;
777 diff -pruN --exclude build ./demo_clean/src/LAppTextureManager.cpp ./demo_dev/src/LAppTextureManager.cpp
778 --- ./demo_clean/src/LAppTextureManager.cpp 2025-05-29 18:28:26.250309900 +0100
779 +++ ./demo_dev/src/LAppTextureManager.cpp 2025-05-29 23:51:06.229853200 +0100
780 @@ -89,6 +89,46 @@ LAppTextureManager::TextureInfo* LAppTex
784 +LAppTextureManager::TextureInfo* LAppTextureManager::CreateTextureFromColor(
785 + uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha
788 + constexpr int width = 8, height = 8;
790 + uint8_t pixels[height][width][4];
791 + for (std::size_t h = 0; h < height; h++)
793 + for (std::size_t w = 0; w < width; w++)
795 + pixels[h][w][0] = red;
796 + pixels[h][w][1] = green;
797 + pixels[h][w][2] = blue;
798 + pixels[h][w][3] = alpha;
803 + glGenTextures(1, &textureId);
804 + glBindTexture(GL_TEXTURE_2D, textureId);
805 + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
807 + glGenerateMipmap(GL_TEXTURE_2D);
808 + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
809 + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
810 + glBindTexture(GL_TEXTURE_2D, 0);
813 + LAppTextureManager::TextureInfo* textureInfo = new LAppTextureManager::TextureInfo();
814 + textureInfo->fileName = "";
815 + textureInfo->width = width;
816 + textureInfo->height = height;
817 + textureInfo->id = textureId;
819 + _texturesInfo.PushBack(textureInfo);
821 + return textureInfo;
824 void LAppTextureManager::ReleaseTextures()
826 for (Csm::csmUint32 i = 0; i < _texturesInfo.GetSize(); i++)
827 diff -pruN --exclude build ./demo_clean/src/LAppTextureManager.hpp ./demo_dev/src/LAppTextureManager.hpp
828 --- ./demo_clean/src/LAppTextureManager.hpp 2025-05-29 18:28:26.344512900 +0100
829 +++ ./demo_dev/src/LAppTextureManager.hpp 2025-05-29 23:51:13.635314000 +0100
830 @@ -41,6 +41,8 @@ public:
832 TextureInfo* CreateTextureFromPngFile(std::string fileName);
834 + TextureInfo *CreateTextureFromColor(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha = 255);
839 diff -pruN --exclude build ./demo_clean/src/LAppView.cpp ./demo_dev/src/LAppView.cpp
840 --- ./demo_clean/src/LAppView.cpp 2025-05-29 18:28:25.905329300 +0100
841 +++ ./demo_dev/src/LAppView.cpp 2025-05-29 23:51:22.898336200 +0100
842 @@ -83,12 +83,7 @@ void LAppView::Render()
843 int maxWidth, maxHeight;
844 glfwGetWindowSize(LAppDelegate::GetInstance()->GetWindow(), &maxWidth, &maxHeight);
845 _back->SetWindowSize(maxWidth, maxHeight);
846 - _gear->SetWindowSize(maxWidth, maxHeight);
847 - _power->SetWindowSize(maxWidth, maxHeight);
853 LAppLive2DManager* Live2DManager = LAppLive2DManager::GetInstance();
855 @@ -131,35 +126,17 @@ void LAppView::InitializeSprite()
856 glfwGetWindowSize(LAppDelegate::GetInstance()->GetWindow(), &width, &height);
858 LAppTextureManager* textureManager = LAppDelegate::GetInstance()->GetTextureManager();
859 - const string resourcesPath = ResourcesPath;
861 - string imageName = BackImageName;
862 - LAppTextureManager::TextureInfo* backgroundTexture = textureManager->CreateTextureFromPngFile(resourcesPath + imageName);
864 + LAppTextureManager::TextureInfo* backgroundTexture =
865 + textureManager->CreateTextureFromColor(0, 255, 0);
867 float x = width * 0.5f;
868 float y = height * 0.5f;
869 - float fWidth = static_cast<float>(backgroundTexture->width * 2.0f);
870 - float fHeight = static_cast<float>(height * 0.95f);
871 + float fWidth = static_cast<float>(width);
872 + float fHeight = static_cast<float>(height);
873 _back = new LAppSprite(x, y, fWidth, fHeight, backgroundTexture->id, programId);
875 - imageName = GearImageName;
876 - LAppTextureManager::TextureInfo* gearTexture = textureManager->CreateTextureFromPngFile(resourcesPath + imageName);
878 - x = static_cast<float>(width - gearTexture->width * 0.5f);
879 - y = static_cast<float>(height - gearTexture->height * 0.5f);
880 - fWidth = static_cast<float>(gearTexture->width);
881 - fHeight = static_cast<float>(gearTexture->height);
882 - _gear = new LAppSprite(x, y, fWidth, fHeight, gearTexture->id, programId);
884 - imageName = PowerImageName;
885 - LAppTextureManager::TextureInfo* powerTexture = textureManager->CreateTextureFromPngFile(resourcesPath + imageName);
887 - x = static_cast<float>(width - powerTexture->width * 0.5f);
888 - y = static_cast<float>(powerTexture->height * 0.5f);
889 - fWidth = static_cast<float>(powerTexture->width);
890 - fHeight = static_cast<float>(powerTexture->height);
891 - _power = new LAppSprite(x, y, fWidth, fHeight, powerTexture->id, programId);
896 @@ -198,17 +175,6 @@ void LAppView::OnTouchesEnded(float px,
898 live2DManager->OnTap(x, y);
901 - if (_gear->IsHit(px, py))
903 - live2DManager->NextScene();
907 - if (_power->IsHit(px, py))
909 - LAppDelegate::GetInstance()->AppEnd();
914 diff -pruN --exclude build ./demo_clean/src/main.cpp ./demo_dev/src/main.cpp
915 --- ./demo_clean/src/main.cpp 2025-05-29 18:28:26.046369000 +0100
916 +++ ./demo_dev/src/main.cpp 2025-05-29 23:48:14.989176800 +0100
918 * that can be found at https://www.live2d.com/eula/live2d-open-software-license-agreement_en.html.
922 +#include <stdexcept>
925 +#ifdef __cpp_lib_filesystem
926 +#include <filesystem>
927 +namespace fs = std::filesystem;
929 +#include <experimental/filesystem>
930 +namespace fs = std::experimental::filesystem;
934 #include "LAppDelegate.hpp"
935 -#include <windows.h>
936 +#include "LAppLive2DManager.hpp"
937 +#include "facial_landmark_detector.h"
942 - // Setting the console character encoding to UTF-8
943 - UINT preConsoleOutputCP = GetConsoleOutputCP();
944 - SetConsoleOutputCP(65001);
947 + std::string windowTitle;
948 + std::string rootDir;
952 + std::string modelName;
953 + bool oldId; // If true, translate new (Cubism 3+) parameter IDs to old (Cubism 2.1) IDs
954 + std::string cfgPath; // Path to config file for FacialLandmarkDetector
957 - // create the application instance
958 - if (LAppDelegate::GetInstance()->Initialize() == GL_FALSE)
959 +CmdArgs parseArgv(int argc, char *argv[])
961 + // I think the command-line args are simple enough to not justify using a library...
963 + // Set default values
964 + cmdArgs.windowWidth = 600;
965 + cmdArgs.windowHeight = 600;
966 + cmdArgs.windowTitle = "FacialLandmarksForCubism example";
967 + cmdArgs.rootDir = fs::current_path().string();
968 + cmdArgs.scaleFactor = 4.5f;
969 + cmdArgs.translateX = 0.0f;
970 + cmdArgs.translateY = -3.1f;
971 + cmdArgs.modelName = "Haru";
972 + cmdArgs.oldId = false;
973 + cmdArgs.cfgPath = "";
978 - SetConsoleOutputCP(preConsoleOutputCP);
980 + std::string arg = argv[i];
981 + std::stringstream ss;
983 + if (arg == "--window-width" || arg == "-W") // capital W for consistency with height
986 + if (!(ss >> cmdArgs.windowWidth))
988 + throw std::runtime_error("Invalid argument for window width");
991 + else if (arg == "--window-height" || arg == "-H") // avoiding "-h", typically for help
994 + if (!(ss >> cmdArgs.windowHeight))
996 + throw std::runtime_error("Invalid argument for window height");
999 + else if (arg == "--window-title" || arg == "-t")
1001 + cmdArgs.windowTitle = argv[i + 1];
1003 + else if (arg == "--root-dir" || arg == "-d")
1005 + cmdArgs.rootDir = argv[i + 1];
1007 + else if (arg == "--scale-factor" || arg == "-f")
1009 + ss << argv[i + 1];
1010 + if (!(ss >> cmdArgs.scaleFactor))
1012 + throw std::runtime_error("Invalid argument for scale factor");
1015 + else if (arg == "--translate-x" || arg == "-x")
1017 + ss << argv[i + 1];
1018 + if (!(ss >> cmdArgs.translateX))
1020 + throw std::runtime_error("Invalid argument for translate X");
1023 + else if (arg == "--translate-y" || arg == "-y")
1025 + ss << argv[i + 1];
1026 + if (!(ss >> cmdArgs.translateY))
1028 + throw std::runtime_error("Invalid argument for translate Y");
1031 + else if (arg == "--model" || arg == "-m")
1033 + cmdArgs.modelName = argv[i + 1];
1035 + else if (arg == "--config" || arg == "-c")
1037 + cmdArgs.cfgPath = argv[i + 1];
1039 + else if (arg == "--old-param-id" || arg == "-o")
1041 + cmdArgs.oldId = (argv[i + 1][0] == '1');
1045 + throw std::runtime_error("Unrecognized argument: " + arg);
1051 - LAppDelegate::GetInstance()->Run();
1055 - SetConsoleOutputCP(preConsoleOutputCP);
1056 +int main(int argc, char* argv[])
1058 + auto cmdArgs = parseArgv(argc, argv);
1060 + LAppDelegate *delegate = LAppDelegate::GetInstance();
1062 + if (!delegate->Initialize(cmdArgs.windowWidth,
1063 + cmdArgs.windowHeight,
1064 + cmdArgs.windowTitle.c_str()))
1066 + throw std::runtime_error("Unable to initialize LAppDelegate");
1069 + FacialLandmarkDetector detector(cmdArgs.cfgPath);
1071 + std::thread detectorThread(&FacialLandmarkDetector::mainLoop,
1074 + LAppLive2DManager *manager = LAppLive2DManager::GetInstance();
1075 + manager->SetModel(cmdArgs.modelName, cmdArgs.oldId);
1077 + manager->SetProjectionScaleTranslate(cmdArgs.scaleFactor,
1078 + cmdArgs.translateX,
1079 + cmdArgs.translateY);
1080 + manager->SetFacialLandmarkDetector(&detector);
1085 + detectorThread.join();