1. 规范了一些Live2D实例代码的内容

2. 增加了窗口大小随着模型大小变化而变化的功能
This commit is contained in:
Misaki
2025-12-05 17:26:18 +08:00
parent 5c007aa8d9
commit 09a4492f07
12 changed files with 120 additions and 80 deletions
+14 -14
View File
@@ -159,43 +159,43 @@ public:
void Update() const; void Update() const;
/** /**
* Returns the width of the canvas. * Returns the width of the canvas.<br>
* * 返回画布的像素宽度。
* @return Width of the canvas in pixels * @return Width of the canvas in pixels
*/ */
csmFloat32 GetCanvasWidthPixel() const; csmFloat32 GetCanvasWidthPixel() const;
/** /**
* Returns the height of the canvas. * Returns the height of the canvas.<br>
* * 返回画布的像素高度。
* @return Height of the canvas in pixels * @return Height of the canvas in pixels
*/ */
csmFloat32 GetCanvasHeightPixel() const; csmFloat32 GetCanvasHeightPixel() const;
/** /**
* Returns the pixels per unit (PPU). * Returns the pixels per unit (PPU). <br>
* * 返回 PPUPixels Per Unit),即 Live2D 坐标系中的 $1.0$ 单位对应多少像素。 (Misaki注解)
* @return Pixels per unit * @return Pixels per unit
*/ */
csmFloat32 GetPixelsPerUnit() const; csmFloat32 GetPixelsPerUnit() const;
/** /**
* Returns the width of the canvas. * Returns the width of the canvas.
* * 返回画布在 PPU 单位下的宽度(例如 1.0)
* @return Width of the canvas in PPU (pixels per unit) * @return Width of the canvas in PPU (pixels per unit)
*/ */
csmFloat32 GetCanvasWidth() const; csmFloat32 GetCanvasWidth() const;
/** /**
* Returns the height of the canvas. * Returns the height of the canvas.
* * 返回画布在 PPU 单位下的高度(例如 2.155300)。
* @return Height of the canvas in PPU (pixels per unit) * @return Height of the canvas in PPU (pixels per unit)
*/ */
csmFloat32 GetCanvasHeight() const; csmFloat32 GetCanvasHeight() const;
/** /**
* Returns the index of the part. * Returns the index of the part.
* * 根据部件 ID (例如 PartId::HairFront) 获取其在数组中的索引。
* @param partId Part ID * @param partId Part ID
* *
* @return Index of the part * @return Index of the part
@@ -204,7 +204,7 @@ public:
/** /**
* Returns the ID of the part. * Returns the ID of the part.
* * 根据索引获取部件 ID。
* @param partIndex Index of the part * @param partIndex Index of the part
* @return Part ID * @return Part ID
*/ */
@@ -212,21 +212,21 @@ public:
/** /**
* Returns the number of parts. * Returns the number of parts.
* * 返回模型中部件的总数。
* @return Number of parts * @return Number of parts
*/ */
csmInt32 GetPartCount() const; csmInt32 GetPartCount() const;
/** /**
* Returns the index of the parent parts for the parts. * Returns the index of the parent parts for the parts.
* * 获取每个部件的父部件索引数组,用于确定绘制顺序或层级关系。
* @return Index of parent parts for the parts. * @return Index of parent parts for the parts.
*/ */
const csmInt32* GetPartParentPartIndices() const; const csmInt32* GetPartParentPartIndices() const;
/** /**
* Sets the opacity of the part. * Sets the opacity of the part.
* * 设置或获取部件的不透明度(0.0 到 1.0)。常用于实现部件的动态隐藏或显示效果。
* @param partId Part ID * @param partId Part ID
* @param opacity Opacity * @param opacity Opacity
*/ */
@@ -234,7 +234,7 @@ public:
/** /**
* Sets the opacity of the part. * Sets the opacity of the part.
* * 设置或获取部件的不透明度(0.0 到 1.0)。常用于实现部件的动态隐藏或显示效果。
* @param partIndex Part index * @param partIndex Part index
* @param opacity Part opacity * @param opacity Part opacity
*/ */
+21 -2
View File
@@ -48,6 +48,25 @@ public:
*/ */
int getTapBodyMotionCount(); int getTapBodyMotionCount();
/**
* @brief 获取 Live2D 模型的 Canvas 宽度像素 (在 Live2D 坐标系下)
* @return Canvas 宽度
*/
Live2D::Cubism::Framework::csmFloat32 GetModelCanvasWidthPixel() const
{
// _model 是 CubismModel 的基类指针
return _model ? _model->GetCanvasWidthPixel() : 0.0f;
}
/**
* @brief 获取 Live2D 模型的 Canvas 高度像素 (在 Live2D 坐标系下)
* @return Canvas 高度
*/
Live2D::Cubism::Framework::csmFloat32 GetModelCanvasHeightPixel() const
{
return _model ? _model->GetCanvasHeightPixel() : 0.0f;
}
/** /**
* @brief 启动唇形同步并播放指定的 WAV 文件 * @brief 启动唇形同步并播放指定的 WAV 文件
* @param filePath WAV 文件的路径(csmString 类型) * @param filePath WAV 文件的路径(csmString 类型)
@@ -64,8 +83,8 @@ public:
/** /**
* @brief model3.jsonが置かれたディレクトリとファイルパスからモデルを生成する * @brief model3.jsonが置かれたディレクトリとファイルパスからモデルを生成する \n
* * 从 model3.json 所在的目录和文件路径生成模型
*/ */
void LoadAssets(const Csm::csmChar* dir, const Csm::csmChar* fileName); void LoadAssets(const Csm::csmChar* dir, const Csm::csmChar* fileName);
+6 -6
View File
@@ -63,7 +63,7 @@ bool LAppDelegate::Initialize(GLCore* window)
// Windowの生成_ // Windowの生成_
//_window = glfwCreateWindow(RenderTargetWidth, RenderTargetHeight, "SAMPLE", NULL, NULL); //_window = glfwCreateWindow(RenderTargetWidth, RenderTargetHeight, "SAMPLE", NULL, NULL);
_window = window; // Misaki 修改 _window = window; // Misaki 修改
if (_window == NULL) if (_window == nullptr)
{ {
if (DebugLogEnable) if (DebugLogEnable)
{ {
@@ -217,7 +217,7 @@ void LAppDelegate::update()
LAppDelegate::LAppDelegate(): LAppDelegate::LAppDelegate():
_cubismOption(), _cubismOption(),
_window(NULL), _window(nullptr),
_captured(false), _captured(false),
_mouseX(0.0f), _mouseX(0.0f),
_mouseY(0.0f), _mouseY(0.0f),
@@ -259,7 +259,7 @@ void LAppDelegate::InitializeCubism()
void LAppDelegate::OnMouseCallBack(GLFWwindow* window, int button, int action, int modify) void LAppDelegate::OnMouseCallBack(GLFWwindow* window, int button, int action, int modify)
{ {
if (_view == NULL) if (_view == nullptr)
{ {
return; return;
} }
@@ -292,7 +292,7 @@ void LAppDelegate::OnMouseCallBack(GLFWwindow* window, double x, double y)
{ {
return; return;
} }
if (_view == NULL) if (_view == nullptr)
{ {
return; return;
} }
@@ -313,7 +313,7 @@ GLuint LAppDelegate::CreateShader()
" gl_Position = vec4(position, 1.0);" " gl_Position = vec4(position, 1.0);"
" vuv = uv;" " vuv = uv;"
"}"; "}";
glShaderSource(vertexShaderId, 1, &vertexShader, NULL); glShaderSource(vertexShaderId, 1, &vertexShader, nullptr);
glCompileShader(vertexShaderId); glCompileShader(vertexShaderId);
if(!CheckShader(vertexShaderId)) if(!CheckShader(vertexShaderId))
{ {
@@ -330,7 +330,7 @@ GLuint LAppDelegate::CreateShader()
"void main(void){" "void main(void){"
" gl_FragColor = texture2D(texture, vuv) * baseColor;" " gl_FragColor = texture2D(texture, vuv) * baseColor;"
"}"; "}";
glShaderSource(fragmentShaderId, 1, &fragmentShader, NULL); glShaderSource(fragmentShaderId, 1, &fragmentShader, nullptr);
glCompileShader(fragmentShaderId); glCompileShader(fragmentShaderId);
if (!CheckShader(fragmentShaderId)) if (!CheckShader(fragmentShaderId))
{ {
+16 -11
View File
@@ -29,7 +29,7 @@ using namespace LAppDefine;
using namespace std; using namespace std;
namespace { namespace {
LAppLive2DManager* s_instance = NULL; LAppLive2DManager* s_instance = nullptr;
void FinishedMotion(ACubismMotion* self) void FinishedMotion(ACubismMotion* self)
{ {
@@ -45,7 +45,7 @@ namespace {
LAppLive2DManager* LAppLive2DManager::GetInstance() LAppLive2DManager* LAppLive2DManager::GetInstance()
{ {
if (s_instance == NULL) if (s_instance == nullptr)
{ {
s_instance = new LAppLive2DManager(); s_instance = new LAppLive2DManager();
} }
@@ -55,22 +55,22 @@ LAppLive2DManager* LAppLive2DManager::GetInstance()
void LAppLive2DManager::ReleaseInstance() void LAppLive2DManager::ReleaseInstance()
{ {
if (s_instance != NULL) if (s_instance != nullptr)
{ {
delete s_instance; delete s_instance;
} }
s_instance = NULL; s_instance = nullptr;
} }
LAppLive2DManager::LAppLive2DManager() LAppLive2DManager::LAppLive2DManager()
: _viewMatrix(NULL) : _viewMatrix(nullptr)
, _sceneIndex(0) , _sceneIndex(0)
{ {
_viewMatrix = new CubismMatrix44(); _viewMatrix = new CubismMatrix44();
//SetUpModel(); //SetUpModel();
// Resources/Haru/ Haru.model3.json // Resources/Haru/ Haru.model3.json
LoadModelFromPath("Resources/Live2DModels/KITU17/", "KITU17.model3.json"); LoadModelFromPath("Resources/Live2DModels/KITU17/", "KITU17.model3.json"); // 默认加载的模型
//ChangeScene(_sceneIndex); //ChangeScene(_sceneIndex);
} }
@@ -140,7 +140,7 @@ void LAppLive2DManager::SetUpModel()
if (fs::exists(modelJson)) if (fs::exists(modelJson))
_modelDir.PushBack(csmString(dirName.c_str())); _modelDir.PushBack(csmString(dirName.c_str()));
} }
/* 保持与原代码相同的排序 */ // 保持与原代码相同的排序
qsort(_modelDir.GetPtr(), _modelDir.GetSize(), sizeof(csmString), CompareCsmString); qsort(_modelDir.GetPtr(), _modelDir.GetSize(), sizeof(csmString), CompareCsmString);
#endif #endif
} }
@@ -162,7 +162,7 @@ LAppModel* LAppLive2DManager::GetModel(csmUint32 no) const
return _models[no]; return _models[no];
} }
return NULL; return nullptr;
} }
/** /**
@@ -229,7 +229,7 @@ void LAppLive2DManager::OnUpdate() const
CubismMatrix44 projection; CubismMatrix44 projection;
LAppModel* model = GetModel(i); LAppModel* model = GetModel(i);
if (model->GetModel() == NULL) if (model->GetModel() == nullptr)
{ {
LAppPal::PrintLogLn("Failed to model->GetModel()."); LAppPal::PrintLogLn("Failed to model->GetModel().");
continue; continue;
@@ -247,7 +247,7 @@ void LAppLive2DManager::OnUpdate() const
} }
// 必要があればここで乗算 // 必要があればここで乗算
if (_viewMatrix != NULL) if (_viewMatrix != nullptr)
{ {
projection.MultiplyByMatrix(_viewMatrix); projection.MultiplyByMatrix(_viewMatrix);
} }
@@ -262,7 +262,7 @@ void LAppLive2DManager::OnUpdate() const
LAppDelegate::GetInstance()->GetView()->PostModelDraw(*model); LAppDelegate::GetInstance()->GetView()->PostModelDraw(*model);
} }
} }
#include <AppContext.h>
void LAppLive2DManager::LoadModelFromPath(const std::string& modelPath, const std::string& fileName) void LAppLive2DManager::LoadModelFromPath(const std::string& modelPath, const std::string& fileName)
{ {
csmString modelPathStr(modelPath.c_str()); csmString modelPathStr(modelPath.c_str());
@@ -272,6 +272,11 @@ void LAppLive2DManager::LoadModelFromPath(const std::string& modelPath, const st
_models.PushBack(new LAppModel()); // 这样在加载的时候都使用的models[0]这一个位置,自行实现模型选择器要注意注意 _models.PushBack(new LAppModel()); // 这样在加载的时候都使用的models[0]这一个位置,自行实现模型选择器要注意注意
_models[0]->LoadAssets(modelPathStr.GetRawString(), modelJsonName.GetRawString()); _models[0]->LoadAssets(modelPathStr.GetRawString(), modelJsonName.GetRawString());
// 加载完后根据模型大小来重新设置当前窗口大小
const int width = static_cast<int>(_models[0]->GetModel()->GetCanvasWidthPixel() / 15.0);
const int height = static_cast<int>(_models[0]->GetModel()->GetCanvasHeightPixel() / 15.0);
AppContext::GetGLCore()->setWindowSize(width, height);
LAppPal::PrintLogLn("[APP]窗口尺寸重新设置为: W: %d H: %d", width, height);
/* /*
* 提供一个半透明表示模型的示例。 * 提供一个半透明表示模型的示例。
* 如果定义了USE_RENDER_TARGET或USE_MODEL_RENDER_TARGET * 如果定义了USE_RENDER_TARGET或USE_MODEL_RENDER_TARGET
+18 -18
View File
@@ -47,7 +47,7 @@ namespace {
LAppModel::LAppModel() LAppModel::LAppModel()
: CubismUserModel() : CubismUserModel()
, _modelSetting(NULL) , _modelSetting(nullptr)
, _userTimeSeconds(0.0f) , _userTimeSeconds(0.0f)
{ {
if (MocConsistencyValidationEnable) if (MocConsistencyValidationEnable)
@@ -101,7 +101,7 @@ void LAppModel::LoadAssets(const csmChar* dir, const csmChar* fileName)
SetupModel(setting); SetupModel(setting);
if (_model == NULL) if (_model == nullptr)
{ {
LAppPal::PrintLogLn("Failed to LoadAssets()."); LAppPal::PrintLogLn("Failed to LoadAssets().");
return; return;
@@ -123,7 +123,7 @@ void LAppModel::SetupModel(ICubismModelSetting* setting)
csmSizeInt size; csmSizeInt size;
//Cubism Model //Cubism Model
if (strcmp(_modelSetting->GetModelFileName(), "") != 0) if (strcmp(_modelSetting->GetModelFileName(), "") != 0) // 如果模型文件名不为空
{ {
csmString path = _modelSetting->GetModelFileName(); csmString path = _modelSetting->GetModelFileName();
path = _modelHomeDir + path; path = _modelHomeDir + path;
@@ -153,10 +153,10 @@ void LAppModel::SetupModel(ICubismModelSetting* setting)
if (motion) if (motion)
{ {
if (_expressions[name] != NULL) if (_expressions[name] != nullptr)
{ {
ACubismMotion::Delete(_expressions[name]); ACubismMotion::Delete(_expressions[name]);
_expressions[name] = NULL; _expressions[name] = nullptr;
} }
_expressions[name] = motion; _expressions[name] = motion;
} }
@@ -240,7 +240,7 @@ void LAppModel::SetupModel(ICubismModelSetting* setting)
} }
} }
if (_modelSetting == NULL || _modelMatrix == NULL) if (_modelSetting == nullptr || _modelMatrix == nullptr)
{ {
LAppPal::PrintLogLn("Failed to SetupModel()."); LAppPal::PrintLogLn("Failed to SetupModel().");
return; return;
@@ -258,11 +258,11 @@ void LAppModel::SetupModel(ICubismModelSetting* setting)
const csmChar* group = _modelSetting->GetMotionGroupName(i); const csmChar* group = _modelSetting->GetMotionGroupName(i);
PreloadMotionGroup(group); PreloadMotionGroup(group);
} }
_motionManager->StopAllMotions(); _motionManager->StopAllMotions();
_updating = false; _updating = false;
_initialized = true; _initialized = true;
LAppPal::PrintLogLn("[APP]当前模型像素大小: H: %lf W: %lf", GetModelCanvasHeightPixel(), GetModelCanvasWidthPixel());
} }
void LAppModel::PreloadMotionGroup(const csmChar* group) void LAppModel::PreloadMotionGroup(const csmChar* group)
@@ -301,7 +301,7 @@ void LAppModel::PreloadMotionGroup(const csmChar* group)
} }
tmpMotion->SetEffectIds(_eyeBlinkIds, _lipSyncIds); tmpMotion->SetEffectIds(_eyeBlinkIds, _lipSyncIds);
if (_motions[name] != NULL) if (_motions[name] != nullptr)
{ {
ACubismMotion::Delete(_motions[name]); ACubismMotion::Delete(_motions[name]);
} }
@@ -389,14 +389,14 @@ void LAppModel::Update()
// まばたき 眨眼 // まばたき 眨眼
if (!motionUpdated) if (!motionUpdated)
{ {
if (_eyeBlink != NULL) if (_eyeBlink != nullptr)
{ {
// メインモーションの更新がないとき 当主动作没有更新时 // メインモーションの更新がないとき 当主动作没有更新时
_eyeBlink->UpdateParameters(_model, deltaTimeSeconds); // 目パチ _eyeBlink->UpdateParameters(_model, deltaTimeSeconds); // 目パチ
} }
} }
if (_expressionManager != NULL) if (_expressionManager != nullptr)
{ {
_expressionManager->UpdateMotion(_model, deltaTimeSeconds); // 表情でパラメータ更新(相対変化) _expressionManager->UpdateMotion(_model, deltaTimeSeconds); // 表情でパラメータ更新(相対変化)
} }
@@ -415,13 +415,13 @@ void LAppModel::Update()
_model->AddParameterValue(_idParamEyeBallY, _dragY); _model->AddParameterValue(_idParamEyeBallY, _dragY);
// 呼吸など // 呼吸など
if (_breath != NULL) if (_breath != nullptr)
{ {
_breath->UpdateParameters(_model, deltaTimeSeconds); _breath->UpdateParameters(_model, deltaTimeSeconds);
} }
// 物理演算の設定 // 物理演算の設定
if (_physics != NULL) if (_physics != nullptr)
{ {
_physics->Evaluate(_model, deltaTimeSeconds); _physics->Evaluate(_model, deltaTimeSeconds);
} }
@@ -455,7 +455,7 @@ void LAppModel::Update()
} }
// ポーズの設定 // ポーズの設定
if (_pose != NULL) if (_pose != nullptr)
{ {
_pose->UpdateParameters(_model, deltaTimeSeconds); _pose->UpdateParameters(_model, deltaTimeSeconds);
} }
@@ -516,7 +516,7 @@ CubismMotionQueueEntryHandle LAppModel::StartMotion(const csmChar* group, csmInt
CubismMotion* motion = static_cast<CubismMotion*>(_motions[name.GetRawString()]); CubismMotion* motion = static_cast<CubismMotion*>(_motions[name.GetRawString()]);
csmBool autoDelete = false; csmBool autoDelete = false;
if (motion == NULL) if (motion == nullptr)
{ {
csmString path = fileName; csmString path = fileName;
path = _modelHomeDir + path; path = _modelHomeDir + path;
@@ -524,7 +524,7 @@ CubismMotionQueueEntryHandle LAppModel::StartMotion(const csmChar* group, csmInt
csmByte* buffer; csmByte* buffer;
csmSizeInt size; csmSizeInt size;
buffer = CreateBuffer(path.GetRawString(), &size); buffer = CreateBuffer(path.GetRawString(), &size);
motion = static_cast<CubismMotion*>(LoadMotion(buffer, size, NULL, onFinishedMotionHandler)); motion = static_cast<CubismMotion*>(LoadMotion(buffer, size, nullptr, onFinishedMotionHandler));
if (motion) if (motion)
{ {
@@ -618,7 +618,7 @@ int LAppModel::getTapBodyMotionCount()
void LAppModel::DoDraw() void LAppModel::DoDraw()
{ {
if (_model == NULL) if (_model == nullptr)
{ {
return; return;
} }
@@ -628,7 +628,7 @@ void LAppModel::DoDraw()
void LAppModel::Draw(CubismMatrix44& matrix) void LAppModel::Draw(CubismMatrix44& matrix)
{ {
if (_model == NULL) if (_model == nullptr)
{ {
return; return;
} }
@@ -667,7 +667,7 @@ void LAppModel::SetExpression(const csmChar* expressionID)
LAppPal::PrintLogLn("[APP]expression: [%s]", expressionID); LAppPal::PrintLogLn("[APP]expression: [%s]", expressionID);
} }
if (motion != NULL) if (motion != nullptr)
{ {
_expressionManager->StartMotionPriority(motion, false, PriorityForce); _expressionManager->StartMotionPriority(motion, false, PriorityForce);
} }
+3 -3
View File
@@ -25,7 +25,7 @@ LAppView::LAppView():
//_back(NULL), //_back(NULL),
//_gear(NULL), //_gear(NULL),
//_power(NULL), //_power(NULL),
_renderSprite(NULL), _renderSprite(nullptr),
_renderTarget(SelectTarget_None) _renderTarget(SelectTarget_None)
{ {
_clearColor[0] = 1.0f; _clearColor[0] = 1.0f;
@@ -268,7 +268,7 @@ float LAppView::TransformScreenY(float deviceY) const
void LAppView::PreModelDraw(LAppModel& refModel) void LAppView::PreModelDraw(LAppModel& refModel)
{ {
// 別のレンダリングターゲットへ向けて描画する場合の使用するフレームバッファ // 別のレンダリングターゲットへ向けて描画する場合の使用するフレームバッファ
Csm::Rendering::CubismOffscreenSurface_OpenGLES2* useTarget = NULL; Csm::Rendering::CubismOffscreenSurface_OpenGLES2* useTarget = nullptr;
if (_renderTarget != SelectTarget_None) if (_renderTarget != SelectTarget_None)
{// 別のレンダリングターゲットへ向けて描画する場合 {// 別のレンダリングターゲットへ向けて描画する場合
@@ -299,7 +299,7 @@ void LAppView::PreModelDraw(LAppModel& refModel)
void LAppView::PostModelDraw(LAppModel& refModel) void LAppView::PostModelDraw(LAppModel& refModel)
{ {
// 別のレンダリングターゲットへ向けて描画する場合の使用するフレームバッファ // 別のレンダリングターゲットへ向けて描画する場合の使用するフレームバッファ
Csm::Rendering::CubismOffscreenSurface_OpenGLES2* useTarget = NULL; Csm::Rendering::CubismOffscreenSurface_OpenGLES2* useTarget = nullptr;
if (_renderTarget != SelectTarget_None) if (_renderTarget != SelectTarget_None)
{// 別のレンダリングターゲットへ向けて描画する場合 {// 別のレンダリングターゲットへ向けて描画する場合
+5 -3
View File
@@ -8,11 +8,13 @@
(本项目由Yosuga[Qt5] 发展更新而来,项目架构与代码都有所不同,最显著的特点是本项目支持多平台) (本项目由Yosuga[Qt5] 发展更新而来,项目架构与代码都有所不同,最显著的特点是本项目支持多平台)
环境为: 环境为:
cmake version 3.31.3 - cmake version 3.5
Qt6.6.3 - C++ 20
IDE: Clion - Qt6.6.3
- IDE: Clion
如何构建本项目: 如何构建本项目:
+2 -2
View File
@@ -18,7 +18,7 @@ int main(int argc, char *argv[])
// 设置日志过滤规则,将这个特定分类的警告级别设置为“关闭” // 设置日志过滤规则,将这个特定分类的警告级别设置为“关闭”
QLoggingCategory::setFilterRules("qt.multimedia.ffmpeg.libsymbolsresolver.warning=false"); QLoggingCategory::setFilterRules("qt.multimedia.ffmpeg.libsymbolsresolver.warning=false");
#endif #endif
GLCore w(360, 480); GLCore w(360, 480); // 创建默认的窗口
w.show(); w.show();
return a.exec(); return QApplication::exec();
} }
+6 -3
View File
@@ -4,7 +4,7 @@
#include <QOpenGLWidget> #include <QOpenGLWidget>
#include "menu.h" #include "menu.h"
class GLCore : public QOpenGLWidget class GLCore final : public QOpenGLWidget
{ {
Q_OBJECT Q_OBJECT
@@ -19,15 +19,18 @@ public:
// 删除移动运算符 // 删除移动运算符
GLCore& operator=(GLCore&&) = delete; GLCore& operator=(GLCore&&) = delete;
~GLCore(); ~GLCore() override;
// 帧率控制 // 帧率控制
void setFrameRate(double fps); void setFrameRate(double fps);
double getFrameRate(); [[nodiscard]] double getFrameRate() const;
// 帧率表 // 帧率表
static QMap<QString, double> getFrameRateMap(); static QMap<QString, double> getFrameRateMap();
static QStringList getFrameRateList(); static QStringList getFrameRateList();
// 安全地设置窗口的实际像素尺寸
void setWindowSize(int w, int h);
void mouseMoveEvent(QMouseEvent* event) override; void mouseMoveEvent(QMouseEvent* event) override;
void mousePressEvent(QMouseEvent* event) override; void mousePressEvent(QMouseEvent* event) override;
void mouseReleaseEvent(QMouseEvent* event) override; void mouseReleaseEvent(QMouseEvent* event) override;
+26 -11
View File
@@ -61,7 +61,7 @@ GLCore::GLCore(int w, int h, QWidget *parent)
TextRenderer::getInstance()->setGravity(600.0f); // 更快的下坠速度 TextRenderer::getInstance()->setGravity(600.0f); // 更快的下坠速度
TextRenderer::getInstance()->setDampFactor(0.85f); // 更强的弹性效果 TextRenderer::getInstance()->setDampFactor(0.85f); // 更强的弹性效果
this->setWindowFlag(Qt::FramelessWindowHint); // 设置无边框窗口 // this->setWindowFlag(Qt::FramelessWindowHint); // 设置无边框窗口
this->setWindowFlag(Qt::WindowStaysOnTopHint); // 设置窗口始终在顶部 this->setWindowFlag(Qt::WindowStaysOnTopHint); // 设置窗口始终在顶部
this->setWindowFlag(Qt::Tool); // 隐藏应用程序图标 this->setWindowFlag(Qt::Tool); // 隐藏应用程序图标
this->setAttribute(Qt::WA_TranslucentBackground); // 设置窗口背景透明 this->setAttribute(Qt::WA_TranslucentBackground); // 设置窗口背景透明
@@ -75,7 +75,7 @@ GLCore::GLCore(int w, int h, QWidget *parent)
frameTimer->start(static_cast<int>((1.0 / frameRate) * 1000)); // 使用成员变量计算间隔 frameTimer->start(static_cast<int>((1.0 / frameRate) * 1000)); // 使用成员变量计算间隔
// 启用鼠标跟踪,不启用鼠标按下才会回调mouseMoveEvent函数 // 启用鼠标跟踪,不启用的话鼠标按下才会回调mouseMoveEvent函数
this->setMouseTracking(true); this->setMouseTracking(true);
// 连接一些必要的信号与槽 // 连接一些必要的信号与槽
@@ -114,7 +114,7 @@ void GLCore::setFrameRate(double fps)
} }
// 获取当前帧率 // 获取当前帧率
double GLCore::getFrameRate() double GLCore::getFrameRate() const
{ {
return frameRate; return frameRate;
} }
@@ -163,8 +163,8 @@ void GLCore::closeEvent(QCloseEvent* event)
void GLCore::mouseMoveEvent(QMouseEvent* event) void GLCore::mouseMoveEvent(QMouseEvent* event)
{ {
LAppDelegate::GetInstance()->GetView()->OnTouchesMoved( LAppDelegate::GetInstance()->GetView()->OnTouchesMoved(
event->position().x(), static_cast<float>(event->position().x()),
event->position().y() static_cast<float>(event->position().y())
); );
if (isLeftPressed) { if (isLeftPressed) {
@@ -176,8 +176,8 @@ void GLCore::mouseMoveEvent(QMouseEvent* event)
void GLCore::mousePressEvent(QMouseEvent* event) void GLCore::mousePressEvent(QMouseEvent* event)
{ {
LAppDelegate::GetInstance()->GetView()->OnTouchesBegan( LAppDelegate::GetInstance()->GetView()->OnTouchesBegan(
event->position().x(), static_cast<float>(event->position().x()),
event->position().y() static_cast<float>(event->position().y())
); );
if (event->button() == Qt::LeftButton) { if (event->button() == Qt::LeftButton) {
@@ -198,8 +198,8 @@ void GLCore::mousePressEvent(QMouseEvent* event)
void GLCore::mouseReleaseEvent(QMouseEvent* event) void GLCore::mouseReleaseEvent(QMouseEvent* event)
{ {
LAppDelegate::GetInstance()->GetView()->OnTouchesEnded( LAppDelegate::GetInstance()->GetView()->OnTouchesEnded(
event->position().x(), static_cast<float>(event->position().x()),
event->position().y() static_cast<float>(event->position().y())
); );
if (event->button() == Qt::LeftButton) { if (event->button() == Qt::LeftButton) {
@@ -218,16 +218,31 @@ void GLCore::initializeGL()
void GLCore::paintGL() void GLCore::paintGL()
{ {
LAppDelegate::GetInstance()->update(); LAppDelegate::GetInstance()->update(); // Live2D画面渲染
// 渲染文本 // 渲染文本
TextRenderer::getInstance()->update(); TextRenderer::getInstance()->update();
TextRenderer::getInstance()->render(); TextRenderer::getInstance()->render();
} }
void GLCore::resizeGL(int w, int h) void GLCore::resizeGL(const int w, const int h)
{ {
// 设置文本渲染器窗口大小 // 设置文本渲染器窗口大小
TextRenderer::getInstance()->setWindowSize(w, h); TextRenderer::getInstance()->setWindowSize(w, h);
LAppDelegate::GetInstance()->resize(w, h); LAppDelegate::GetInstance()->resize(w, h);
}
// 设置窗口大小,并触发 resizeGL 事件
void GLCore::setWindowSize(const int w, const int h)
{
// 检查是否需要更新,避免重复调用
if (this->width() == w && this->height() == h) {
return;
}
// 调用 QWidget::resize 或 setFixedSize 来改变窗口的实际尺寸
setFixedSize(w, h);
// 调用 setFixedSize 会自动触发 QOpenGLWidget 的 resizeEvent
// 进而调用 resizeGL(w, h),无需手动调用 resizeGL
} }
+1 -5
View File
@@ -1,9 +1,7 @@
// //
// Created by Administrator on 2025/2/16. // Created by Administrator on 2025/2/16.
// //
#pragma once
#ifndef AIRI_DESKTOPGRIL_TEXTRENDERER_H
#define AIRI_DESKTOPGRIL_TEXTRENDERER_H
#include <QOpenGLWidget> #include <QOpenGLWidget>
#include <QVector> #include <QVector>
@@ -99,5 +97,3 @@ private:
float gravity; /// 重力加速度(像素/秒²) float gravity; /// 重力加速度(像素/秒²)
float dampFactor; /// 碰撞阻尼系数 float dampFactor; /// 碰撞阻尼系数
}; };
#endif //AIRI_DESKTOPGRIL_TEXTRENDERER_H
+2 -2
View File
@@ -198,8 +198,8 @@ void TextRenderer::update()
// 最终居中定位 // 最终居中定位
int totalWidth = 0; int totalWidth = 0;
for (int w : instance.charWidths) totalWidth += w; for (const int w : instance.charWidths) totalWidth += w;
int startX = (windowWidth - totalWidth) / 2; const int startX = (windowWidth - totalWidth) / 2;
int currentX = startX; int currentX = startX;
instance.charPositions.clear(); instance.charPositions.clear();