1. 抽离了LApp的部分内容,以解耦其对Qt的依赖,并且尝试了拓展多渲染后端支持。
This commit is contained in:
+42
@@ -0,0 +1,42 @@
|
||||
# LAppLive2D — Live2D SDK 示例应用层,编译为静态库
|
||||
# 依赖:Framework(libFramework.a) + Live2DCubismCore(libLive2DCubismCore.a)
|
||||
# 无 Qt 依赖 — 完全解耦,仅依赖 OpenGL/GLES 头文件 + Cubism SDK
|
||||
|
||||
file(GLOB_RECURSE LAppLive2D_SOURCES
|
||||
CONFIGURE_DEPENDS
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/Src/*.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/Inc/*.hpp"
|
||||
)
|
||||
|
||||
add_library(lapp_live2d STATIC ${LAppLive2D_SOURCES})
|
||||
|
||||
# =============================================
|
||||
# 自身的公开头文件目录
|
||||
# =============================================
|
||||
target_include_directories(lapp_live2d
|
||||
PUBLIC
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/Inc"
|
||||
)
|
||||
|
||||
# =============================================
|
||||
# Live2D SDK 头文件(Framework + Core + stb)
|
||||
# 这些是 lapp_live2d 编译时必需的,通过 PUBLIC 发布给最终链接目标
|
||||
# =============================================
|
||||
target_include_directories(lapp_live2d
|
||||
PUBLIC
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/../Framework/src"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/../Core/include"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/../stb"
|
||||
)
|
||||
|
||||
# =============================================
|
||||
# 链接依赖 — 注意链接顺序!
|
||||
# lapp_live2d → Framework → Live2DCubismCore
|
||||
# Framework 内部使用了 Live2DCubismCore 的符号,所以 Core 必须在 Framework 之后
|
||||
# lapp_live2d 无 Qt 依赖,开发者可自由选择 UI 后端(Qt/SDL/GLFW等)
|
||||
# =============================================
|
||||
target_link_libraries(lapp_live2d
|
||||
PUBLIC
|
||||
Framework # Live2D Framework 静态库(IMPORTED,由父CMakeLists定义)
|
||||
Live2DCubismCore # Live2D Core 静态库(IMPORTED,由父CMakeLists定义)
|
||||
)
|
||||
@@ -0,0 +1,102 @@
|
||||
//
|
||||
// Created by misaki on 2026/6/23.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#include "IRenderContext.hpp"
|
||||
#include "LAppOpenGL.hpp"
|
||||
|
||||
class GLRenderContext final : public IRenderContext {
|
||||
public:
|
||||
void Clear(float r, float g, float b, float a) override {
|
||||
glClearColor(r, g, b, a);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
|
||||
void ClearDepth(float depth) override {
|
||||
LAPP_GL_CLEAR_DEPTH(depth);
|
||||
}
|
||||
|
||||
void SetViewport(int x, int y, int w, int h) override {
|
||||
glViewport(x, y, w, h);
|
||||
}
|
||||
|
||||
uintptr_t CreateShaderProgram() override {
|
||||
return CompileShader();
|
||||
}
|
||||
|
||||
uintptr_t GetShaderProgram() const override {
|
||||
return _programId;
|
||||
}
|
||||
|
||||
void InitializeGLState() override {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
}
|
||||
|
||||
private:
|
||||
GLuint _programId = 0;
|
||||
|
||||
GLuint CompileShader() {
|
||||
if (_programId) return _programId;
|
||||
|
||||
#if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_ES_3) || defined(EMBEDDED_LINUX)
|
||||
const char* vertexShader =
|
||||
"#version 100\n"
|
||||
"attribute vec3 position;\n"
|
||||
"attribute vec2 uv;\n"
|
||||
"varying vec2 vuv;\n"
|
||||
"void main() {\n"
|
||||
" gl_Position = vec4(position, 1.0);\n"
|
||||
" vuv = uv;\n"
|
||||
"}\n";
|
||||
const char* fragmentShader =
|
||||
"#version 100\n"
|
||||
"precision mediump float;\n"
|
||||
"varying vec2 vuv;\n"
|
||||
"uniform sampler2D texture;\n"
|
||||
"uniform vec4 baseColor;\n"
|
||||
"void main() {\n"
|
||||
" gl_FragColor = texture2D(texture, vuv) * baseColor;\n"
|
||||
"}\n";
|
||||
#else
|
||||
const char* vertexShader =
|
||||
"#version 120\n"
|
||||
"attribute vec3 position;\n"
|
||||
"attribute vec2 uv;\n"
|
||||
"varying vec2 vuv;\n"
|
||||
"void main(void) {\n"
|
||||
" gl_Position = vec4(position, 1.0);\n"
|
||||
" vuv = uv;\n"
|
||||
"}\n";
|
||||
const char* fragmentShader =
|
||||
"#version 120\n"
|
||||
"varying vec2 vuv;\n"
|
||||
"uniform sampler2D texture;\n"
|
||||
"uniform vec4 baseColor;\n"
|
||||
"void main(void) {\n"
|
||||
" gl_FragColor = texture2D(texture, vuv) * baseColor;\n"
|
||||
"}\n";
|
||||
#endif
|
||||
|
||||
GLuint vertId = glCreateShader(GL_VERTEX_SHADER);
|
||||
glShaderSource(vertId, 1, &vertexShader, nullptr);
|
||||
glCompileShader(vertId);
|
||||
|
||||
GLuint fragId = glCreateShader(GL_FRAGMENT_SHADER);
|
||||
glShaderSource(fragId, 1, &fragmentShader, nullptr);
|
||||
glCompileShader(fragId);
|
||||
|
||||
_programId = glCreateProgram();
|
||||
glAttachShader(_programId, vertId);
|
||||
glAttachShader(_programId, fragId);
|
||||
glLinkProgram(_programId);
|
||||
glUseProgram(_programId);
|
||||
|
||||
glDeleteShader(vertId);
|
||||
glDeleteShader(fragId);
|
||||
return _programId;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// Created by misaki on 2026/6/23.
|
||||
//
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
|
||||
class IRenderContext {
|
||||
public:
|
||||
virtual ~IRenderContext() = default;
|
||||
|
||||
virtual void Clear(float r, float g, float b, float a) = 0;
|
||||
virtual void ClearDepth(float depth) = 0;
|
||||
virtual void SetViewport(int x, int y, int w, int h) = 0;
|
||||
virtual uintptr_t CreateShaderProgram() = 0;
|
||||
virtual uintptr_t GetShaderProgram() const = 0;
|
||||
virtual void InitializeGLState() = 0;
|
||||
};
|
||||
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// Created by misaki on 2026/6/23.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
|
||||
class ISpriteRenderer {
|
||||
public:
|
||||
virtual ~ISpriteRenderer() = default;
|
||||
|
||||
virtual void SetColor(float r, float g, float b, float a) = 0;
|
||||
virtual void SetWindowSize(int w, int h) = 0;
|
||||
virtual void RenderImmidiate(uintptr_t textureId,
|
||||
const float uvVertex[8]) const = 0;
|
||||
virtual bool IsHit(float px, float py) const = 0;
|
||||
virtual void ResetRect(float x, float y, float w, float h) = 0;
|
||||
virtual uintptr_t GetTextureId() const = 0;
|
||||
};
|
||||
+26
-7
@@ -9,11 +9,12 @@
|
||||
|
||||
#include "LAppOpenGL.hpp"
|
||||
#include "LAppAllocator.hpp"
|
||||
#include "GLCore.h"
|
||||
#include "IRenderContext.hpp"
|
||||
#include <functional>
|
||||
|
||||
class LAppView;
|
||||
class LAppTextureManager;
|
||||
class GLCore;
|
||||
// class QWidget; // [Misaki] 已完全解耦Qt
|
||||
|
||||
/**
|
||||
* @brief アプリケーションクラス。
|
||||
@@ -37,17 +38,29 @@ public:
|
||||
static void ReleaseInstance();
|
||||
|
||||
// 新增
|
||||
// resize 由应用层(GLCore::resizeGL)调用,通知LApp窗口尺寸变更
|
||||
void resize(int width, int height);
|
||||
|
||||
// 新增
|
||||
void update();
|
||||
|
||||
IRenderContext* GetRenderContext() const { return _renderContext; }
|
||||
void SetRenderContext(IRenderContext* ctx) { _renderContext = ctx; }
|
||||
|
||||
// [Misaki] 窗口大小变更回调 — 解耦 AppContext/GLCore 依赖
|
||||
// 当模型加载后需要调整窗口大小时,LAppLive2DManager 通过此回调通知应用层
|
||||
using WindowResizeFunc = std::function<void(int width, int height)>;
|
||||
void SetWindowResizeCallback(WindowResizeFunc cb) { _onResizeWindow = std::move(cb); }
|
||||
void NotifyWindowResize(int width, int height) { if (_onResizeWindow) _onResizeWindow(width, height); }
|
||||
|
||||
/**
|
||||
* @brief APPに必要なものを初期化する。
|
||||
* @param windowWidth 窗口宽度(像素)
|
||||
* @param windowHeight 窗口高度(像素)
|
||||
*/
|
||||
//bool Initialize();
|
||||
bool Initialize(GLCore* window);
|
||||
// bool Initialize(GLCore* window); // [Misaki] 原
|
||||
// bool Initialize(QWidget* window); // [Misaki] 中间解耦版本
|
||||
bool Initialize(int windowWidth, int windowHeight); // [Misaki] 完全解耦Qt,仅传入尺寸
|
||||
|
||||
/**
|
||||
* @brief 解放する。
|
||||
@@ -86,9 +99,12 @@ public:
|
||||
GLuint CreateShader();
|
||||
|
||||
/**
|
||||
* @brief Window情報を取得する。
|
||||
* @brief Window尺寸を取得する。
|
||||
*/
|
||||
GLCore* GetWindow() { return _window; } // Misaki 修改
|
||||
// GLCore* GetWindow() { return _window; } // [Misaki] 原
|
||||
// QWidget* GetWindow() { return _window; } // [Misaki] 中间版本
|
||||
int GetWindowWidth() const { return _windowWidth; } // [Misaki] 完全解耦Qt
|
||||
int GetWindowHeight() const { return _windowHeight; } // [Misaki] 完全解耦Qt
|
||||
|
||||
/**
|
||||
* @brief View情報を取得する。
|
||||
@@ -128,10 +144,13 @@ private:
|
||||
*/
|
||||
bool CheckShader(GLuint shaderId);
|
||||
|
||||
IRenderContext* _renderContext = nullptr;
|
||||
WindowResizeFunc _onResizeWindow; ///< [Misaki] 窗口大小回调
|
||||
LAppAllocator _cubismAllocator; ///< Cubism SDK Allocator
|
||||
Csm::CubismFramework::Option _cubismOption; ///< Cubism SDK Option
|
||||
//GLFWwindow* _window; ///< OpenGL ウィンドウ
|
||||
GLCore* _window; ///< Misaki 修改
|
||||
// GLCore* _window; ///< Misaki 修改
|
||||
// QWidget* _window; ///< [Misaki] 使用QWidget基类,解耦GLCore
|
||||
LAppView* _view; ///< View情報
|
||||
bool _captured; ///< クリックしているか
|
||||
float _mouseX; ///< マウスX座標
|
||||
|
||||
+3
-1
@@ -17,6 +17,7 @@
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include "LAppOpenGL.hpp"
|
||||
/**
|
||||
* @brief ユーザーが実際に使用するモデルの実装クラス<br>
|
||||
* モデル生成、機能コンポーネント生成、更新処理とレンダリングの呼び出しを行う。
|
||||
@@ -286,5 +287,6 @@ private:
|
||||
Live2D::Cubism::Framework::csmFloat32 alpha = 0.8f; // 滤波系数,范围在0到1之间,值越小,平滑效果越强
|
||||
Live2D::Cubism::Framework::csmFloat32 filteredValue = 0.0f; // 滤波后的值
|
||||
|
||||
Csm::Rendering::CubismOffscreenSurface_OpenGLES2 _renderBuffer; ///< フレームバッファ以外の描画先
|
||||
// Csm::Rendering::CubismOffscreenSurface_OpenGLES2 _renderBuffer; ///< フレームバッファ以外の描画先
|
||||
CUBISM_OFFSCREEN_TYPE _renderBuffer;
|
||||
};
|
||||
|
||||
+22
-1
@@ -22,4 +22,25 @@
|
||||
#define LAPP_GL_CLEAR_DEPTH(d) glClearDepthf(d)
|
||||
#else
|
||||
#define LAPP_GL_CLEAR_DEPTH(d) glClearDepth(d)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define CONCAT_IMPL(a, b) a##b
|
||||
|
||||
#define CONCAT(a, b) CONCAT_IMPL(a, b)
|
||||
|
||||
// 渲染后端编译期类型选择 与 Cubism SDK 的 CubismRenderer::Create() 条件编译对齐
|
||||
#if defined(RENDER_BACKEND_VULKAN)
|
||||
#define RENDERER_BACKEND_TAG Vulkan
|
||||
#elif defined(RENDER_BACKEND_D3D11)
|
||||
#define RENDERER_BACKEND_TAG D3D11
|
||||
#elif defined(RENDER_BACKEND_D3D9)
|
||||
#define RENDERER_BACKEND_TAG D3D9
|
||||
#elif defined(RENDER_BACKEND_METAL)
|
||||
#define RENDERER_BACKEND_TAG Metal
|
||||
#else
|
||||
#define RENDERER_BACKEND_TAG OpenGLES2
|
||||
#endif
|
||||
|
||||
// 类型别名宏,用于 Csm 命名空间下的后端特定类型
|
||||
#define CUBISM_RENDERER_TYPE CONCAT(Csm::Rendering::CubismRenderer_, RENDERER_BACKEND_TAG)
|
||||
#define CUBISM_OFFSCREEN_TYPE CONCAT(Csm::Rendering::CubismOffscreenSurface_, RENDERER_BACKEND_TAG)
|
||||
+19
-9
@@ -8,6 +8,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "LAppOpenGL.hpp"
|
||||
#include "ISpriteRenderer.hpp" // [Misaki] 渲染后端抽象
|
||||
|
||||
/**
|
||||
* @brief スプライトを実装するクラス。
|
||||
@@ -15,7 +16,8 @@
|
||||
* テクスチャID、Rectの管理。
|
||||
*
|
||||
*/
|
||||
class LAppSprite
|
||||
// class LAppSprite // [Misaki] 原
|
||||
class LAppSprite : public ISpriteRenderer // [Misaki] 继承渲染抽象接口
|
||||
{
|
||||
public:
|
||||
/**
|
||||
@@ -40,7 +42,8 @@ public:
|
||||
* @param[in] textureId テクスチャID
|
||||
* @param[in] programId シェーダID
|
||||
*/
|
||||
LAppSprite(float x, float y, float width, float height, GLuint textureId, GLuint programId);
|
||||
// LAppSprite(float x, float y, float width, float height, GLuint textureId, GLuint programId); // [Misaki] 原
|
||||
LAppSprite(float x, float y, float width, float height, uintptr_t textureId, uintptr_t programId); // [Misaki] 抽象类型
|
||||
|
||||
/**
|
||||
* @brief デストラクタ
|
||||
@@ -51,7 +54,8 @@ public:
|
||||
* @brief Getter テクスチャID
|
||||
* @return テクスチャIDを返す
|
||||
*/
|
||||
GLuint GetTextureId() { return _textureId; }
|
||||
// GLuint GetTextureId() { return _textureId; } // [Misaki] 原
|
||||
uintptr_t GetTextureId() const override { return _textureId; } // [Misaki] 抽象类型
|
||||
|
||||
/**
|
||||
* @brief 描画する
|
||||
@@ -63,7 +67,8 @@ public:
|
||||
* @brief テクスチャIDを指定して描画する
|
||||
*
|
||||
*/
|
||||
void RenderImmidiate(GLuint textureId, const GLfloat uvVertex[8]) const;
|
||||
// void RenderImmidiate(GLuint textureId, const GLfloat uvVertex[8]) const; // [Misaki] 原
|
||||
void RenderImmidiate(uintptr_t textureId, const float uvVertex[8]) const override; // [Misaki] 抽象类型
|
||||
|
||||
/**
|
||||
* @brief コンストラクタ
|
||||
@@ -71,7 +76,8 @@ public:
|
||||
* @param[in] pointX x座標
|
||||
* @param[in] pointY y座標
|
||||
*/
|
||||
bool IsHit(float pointX, float pointY) const;
|
||||
// bool IsHit(float pointX, float pointY) const; // [Misaki] 原
|
||||
bool IsHit(float pointX, float pointY) const override; // [Misaki] 接口实现
|
||||
|
||||
/**
|
||||
* @brief 色設定
|
||||
@@ -81,7 +87,8 @@ public:
|
||||
* @param[in] b (0.0~1.0)
|
||||
* @param[in] a (0.0~1.0)
|
||||
*/
|
||||
void SetColor(float r, float g, float b, float a);
|
||||
// void SetColor(float r, float g, float b, float a); // [Misaki] 原
|
||||
void SetColor(float r, float g, float b, float a) override; // [Misaki] 接口实现
|
||||
|
||||
/**
|
||||
* @brief サイズ再設定
|
||||
@@ -91,7 +98,8 @@ public:
|
||||
* @param[in] width 横幅
|
||||
* @param[in] height 高さ
|
||||
*/
|
||||
void ResetRect(float x, float y, float width, float height);
|
||||
// void ResetRect(float x, float y, float width, float height); // [Misaki] 原
|
||||
void ResetRect(float x, float y, float width, float height) override; // [Misaki] 接口实现
|
||||
|
||||
/**
|
||||
* @brief ウインドウサイズ設定
|
||||
@@ -99,10 +107,12 @@ public:
|
||||
* @param[in] width 横幅
|
||||
* @param[in] height 高さ
|
||||
*/
|
||||
void SetWindowSize(int width, int height);
|
||||
// void SetWindowSize(int width, int height); // [Misaki] 原
|
||||
void SetWindowSize(int width, int height) override; // [Misaki] 接口实现
|
||||
|
||||
private:
|
||||
GLuint _textureId; ///< テクスチャID
|
||||
// GLuint _textureId; ///< テクスチャID [Misaki] 原
|
||||
uintptr_t _textureId; ///< テクスチャID [Misaki] 抽象类型
|
||||
Rect _rect; ///< 矩形
|
||||
int _positionLocation; ///< 位置アトリビュート
|
||||
int _uvLocation; ///< UVアトリビュート
|
||||
|
||||
@@ -25,7 +25,8 @@ public:
|
||||
*/
|
||||
struct TextureInfo
|
||||
{
|
||||
GLuint id; ///< テクスチャID
|
||||
// GLuint id; ///< テクスチャID
|
||||
uintptr_t id;
|
||||
int width; ///< 横幅
|
||||
int height; ///< 高さ
|
||||
std::string fileName; ///< ファイル名
|
||||
|
||||
+7
-3
@@ -12,6 +12,7 @@
|
||||
#include <Math/CubismViewMatrix.hpp>
|
||||
#include "CubismFramework.hpp"
|
||||
#include <Rendering/OpenGL/CubismOffscreenSurface_OpenGLES2.hpp>
|
||||
#include "ISpriteRenderer.hpp" // 绘制接口抽象
|
||||
|
||||
class TouchManager;
|
||||
class LAppSprite;
|
||||
@@ -157,14 +158,17 @@ private:
|
||||
TouchManager* _touchManager; ///< タッチマネージャー
|
||||
Csm::CubismMatrix44* _deviceToScreen; ///< デバイスからスクリーンへの行列
|
||||
Csm::CubismViewMatrix* _viewMatrix; ///< viewMatrix
|
||||
GLuint _programId; ///< シェーダID
|
||||
// GLuint _programId; ///< シェーダID
|
||||
uintptr_t _programId; ///< 顶点着色器ID
|
||||
//LAppSprite* _back; ///< 背景画像
|
||||
//LAppSprite* _gear; ///< ギア画像
|
||||
//LAppSprite* _power; ///< 電源画像
|
||||
|
||||
// レンダリング先を別ターゲットにする方式の場合に使用
|
||||
LAppSprite* _renderSprite; ///< モードによっては_renderBufferのテクスチャを描画
|
||||
Csm::Rendering::CubismOffscreenSurface_OpenGLES2 _renderBuffer; ///< モードによってはCubismモデル結果をこっちにレンダリング
|
||||
// LAppSprite* _renderSprite; ///< モードによっては_renderBufferのテクスチャを描画
|
||||
ISpriteRenderer* _renderSprite; ///< 绘制接口抽象
|
||||
// Csm::Rendering::CubismOffscreenSurface_OpenGLES2 _renderBuffer; ///< モードによってはCubismモデル結果をこっちにレンダリング
|
||||
CUBISM_OFFSCREEN_TYPE _renderBuffer;
|
||||
SelectTarget _renderTarget; ///< レンダリング先の選択肢
|
||||
float _clearColor[4]; ///< レンダリングターゲットのクリアカラー
|
||||
};
|
||||
|
||||
+283
@@ -0,0 +1,283 @@
|
||||
# LAppLive2D — 独立 Live2D 渲染库
|
||||
|
||||
## 概述
|
||||
|
||||
`lapp_live2d` 是对 [Live2D Cubism SDK for Native](https://www.live2d.com/download/cubism-sdk/) 的封装层。
|
||||
它将原 SDK 示例代码中的 OpenGL 硬编码抽离为抽象接口,使库本身**不依赖任何窗口框架**(Qt / SDL / GLFW / 自研引擎均可接入)。
|
||||
|
||||
**核心设计原则**:
|
||||
- 零 Qt / GLFW / SDL 依赖 — 仅依赖 C++ 标准库 + OpenGL 头文件 + Cubism SDK
|
||||
- 渲染后端通过 `IRenderContext` / `ISpriteRenderer` 抽象接口注入
|
||||
- 窗口尺寸变更通过 `std::function` 回调通知,不持有窗口指针
|
||||
- 开发者可自由选择窗口框架,编写自己的 `GLCore`
|
||||
|
||||
---
|
||||
|
||||
## 依赖
|
||||
|
||||
| 依赖 | 说明 |
|
||||
|------|------|
|
||||
| **Live2D Cubism Framework** | `libFramework.a`(静态库,Live2D 官方) |
|
||||
| **Live2D Cubism Core** | `libLive2DCubismCore.a`(静态库,Live2D 官方) |
|
||||
| **OpenGL / OpenGL ES 头文件** | 桌面: `GLEW` + `GLFW`头文件;嵌入式: `EGL` + `GLES2` |
|
||||
| **C++ 标准库** | `std::function`, `cstdint` 等 |
|
||||
|
||||
不依赖任何 Qt / SDL / GLFW 链接库。
|
||||
|
||||
---
|
||||
|
||||
## 架构
|
||||
|
||||
```
|
||||
┌───────────────────────────────────────────────────────────┐
|
||||
│ LAppDelegate (单例,应用入口) │
|
||||
│ Initialize(w, h) — 仅需传入窗口尺寸 │
|
||||
│ resize(w, h) — 窗口变更通知 │
|
||||
│ update() — 每帧渲染 │
|
||||
│ SetRenderContext() — 注入渲染后端 │
|
||||
│ SetWindowResizeCallback() — 窗口尺寸变更回调 │
|
||||
│ NotifyWindowResize() — LApp内部通知应用层调整窗口 │
|
||||
│ GetWindowWidth/Height() — 获取当前存储的窗口尺寸 │
|
||||
└──────────────┬────────────────┬────────────────────────────┘
|
||||
│ 持有 │ 持有
|
||||
┌──────────▼──────┐ ┌─────▼──────────────────────────┐
|
||||
│ LAppView │ │ LAppLive2DManager │
|
||||
│ 渲染管理 │ │ 模型生命周期(加载/切换/更新) │
|
||||
│ - 触摸事件 │ │ - OnTap / OnDrag │
|
||||
│ - 坐标变换 │ │ - ModelSizeChange → 回调通知 │
|
||||
│ - Sprite绘制 │ │ │
|
||||
└────────┬─────────┘ └─────┬──────────────────────────┘
|
||||
│ │ 管理
|
||||
┌────────▼───────────────────▼──────┐
|
||||
│ LAppModel : CubismUserModel │
|
||||
│ 单个Live2D模型实例 │
|
||||
│ - 加载(.moc3 / .model3.json) │
|
||||
│ - 动画、物理、口型同步 │
|
||||
│ - 命中检测 (HitTest) │
|
||||
│ - 渲染 (Draw → CubismRenderer) │
|
||||
└───────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 抽象接口
|
||||
|
||||
```
|
||||
IRenderContext ISpriteRenderer
|
||||
│ │
|
||||
├─ Clear(r,g,b,a) ├─ SetColor(r,g,b,a)
|
||||
├─ ClearDepth(d) ├─ SetWindowSize(w,h)
|
||||
├─ SetViewport(x,y,w,h) ├─ RenderImmidiate(texId, uv)
|
||||
├─ CreateShaderProgram() ├─ IsHit(px, py)
|
||||
├─ GetShaderProgram() ├─ ResetRect(x,y,w,h)
|
||||
├─ InitializeGLState() └─ GetTextureId()
|
||||
│
|
||||
└── GLRenderContext (OpenGL实现)
|
||||
- CompileShader() 内部编译 GLSL
|
||||
- Clear → glClear / glClearColor
|
||||
- SetViewport → glViewport
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 接入方式(CMake)
|
||||
|
||||
```cmake
|
||||
# 1. 在父 CMakeLists.txt 中配置 Framework 和 Core(IMPORTED)
|
||||
add_library(Framework STATIC IMPORTED GLOBAL)
|
||||
set_target_properties(Framework PROPERTIES IMPORTED_LOCATION "/path/to/libFramework.a")
|
||||
|
||||
add_library(Live2DCubismCore STATIC IMPORTED GLOBAL)
|
||||
set_target_properties(Live2DCubismCore PROPERTIES IMPORTED_LOCATION "/path/to/libLive2DCubismCore.a")
|
||||
|
||||
# 2. 导入 LAppLive2D 子项目
|
||||
add_subdirectory(3rdparty/Live2D/Src/LAppLive2D)
|
||||
|
||||
# 3. 链接到你的可执行目标
|
||||
target_link_libraries(your_app PRIVATE lapp_live2d)
|
||||
```
|
||||
|
||||
**注意**:LAppLive2D 内部引用 `<GL/glew.h>`(桌面)或 `<GLES2/gl2.h>`(嵌入式),需确保对应的头文件路径可用。参见父项目的 `CMakeLists.txt` 中如何为 `lapp_live2d` 补充平台 GL 头文件路径。
|
||||
|
||||
---
|
||||
|
||||
## 编写自定义窗口(以 Qt 为例)
|
||||
|
||||
```cpp
|
||||
#include <QOpenGLWidget>
|
||||
#include "LAppDelegate.hpp"
|
||||
#include "GLRenderContext.hpp"
|
||||
|
||||
class MyGLCore final : public QOpenGLWidget
|
||||
{
|
||||
void initializeGL() override
|
||||
{
|
||||
// 1. 注入 IRenderContext(OpenGL 实现)
|
||||
LAppDelegate::GetInstance()->SetRenderContext(new GLRenderContext());
|
||||
|
||||
// 2. 注册窗口大小变更回调(模型加载时 LApp 通知你调整窗口)
|
||||
LAppDelegate::GetInstance()->SetWindowResizeCallback([this](int w, int h) {
|
||||
setFixedSize(w, h);
|
||||
});
|
||||
|
||||
// 3. 初始化 LApp(传入当前窗口尺寸)
|
||||
LAppDelegate::GetInstance()->Initialize(width(), height());
|
||||
}
|
||||
|
||||
void resizeGL(int w, int h) override
|
||||
{
|
||||
LAppDelegate::GetInstance()->resize(w, h);
|
||||
}
|
||||
|
||||
void paintGL() override
|
||||
{
|
||||
LAppDelegate::GetInstance()->update();
|
||||
}
|
||||
|
||||
void mousePressEvent(QMouseEvent *ev) override {
|
||||
LAppDelegate::GetInstance()->GetView()->OnTouchesBegan(ev->position().x(), ev->position().y());
|
||||
}
|
||||
void mouseMoveEvent(QMouseEvent *ev) override {
|
||||
LAppDelegate::GetInstance()->GetView()->OnTouchesMoved(ev->position().x(), ev->position().y());
|
||||
}
|
||||
void mouseReleaseEvent(QMouseEvent *ev) override {
|
||||
LAppDelegate::GetInstance()->GetView()->OnTouchesEnded(ev->position().x(), ev->position().y());
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 切换渲染后端
|
||||
|
||||
### 当前支持
|
||||
|
||||
| 后端 | 宏定义 | 说明 |
|
||||
|------|--------|------|
|
||||
| OpenGL ES2 | `RENDER_BACKEND_GLES2` | 嵌入式(RK3566 等) |
|
||||
| OpenGL | `RENDER_BACKEND_OPENGL` | 桌面 Windows / Linux |
|
||||
|
||||
### 添加新后端
|
||||
|
||||
**第 1 步** — 在 `LAppOpenGL.hpp` 的宏分支中加一条:
|
||||
|
||||
```cpp
|
||||
#elif defined(RENDER_BACKEND_VULKAN)
|
||||
#define RENDERER_BACKEND_TAG Vulkan
|
||||
```
|
||||
|
||||
**第 2 步** — 实现 `VulkanRenderContext`(继承 `IRenderContext`),并在其中实现 `Clear` / `SetViewport` / `CreateShaderProgram` 等方法。
|
||||
|
||||
**第 3 步** — CMake 中 `add_definitions(-DRENDER_BACKEND_VULKAN)`。
|
||||
|
||||
**第 4 步** — 在你的窗口 `initializeGL()` 等价函数中创建 `VulkanRenderContext` 注入即可。
|
||||
|
||||
切换后端时 `LAppModel` 和 `LAppView` 中的 `CUBISM_RENDERER_TYPE` / `CUBISM_OFFSCREEN_TYPE` 宏会自动跟随编译宏切换对应的 Cubism SDK 后端类型。
|
||||
|
||||
---
|
||||
|
||||
## API 参考
|
||||
|
||||
### LAppDelegate(单例)
|
||||
|
||||
```cpp
|
||||
// 初始化(必须在 OpenGL 上下文就绪后调用)
|
||||
bool Initialize(int windowWidth, int windowHeight);
|
||||
|
||||
// 每帧调用
|
||||
void update();
|
||||
|
||||
// 窗口尺寸变更
|
||||
void resize(int width, int height);
|
||||
|
||||
// 注入渲染后端
|
||||
void SetRenderContext(IRenderContext* ctx);
|
||||
IRenderContext* GetRenderContext() const;
|
||||
|
||||
// 窗口尺寸回调(模型加载时LApp通知应用层调整窗口)
|
||||
using WindowResizeFunc = std::function<void(int width, int height)>;
|
||||
void SetWindowResizeCallback(WindowResizeFunc cb);
|
||||
|
||||
// 获取当前存储的窗口尺寸
|
||||
int GetWindowWidth() const;
|
||||
int GetWindowHeight() const;
|
||||
|
||||
// 获取 View / TextureManager
|
||||
LAppView* GetView();
|
||||
LAppTextureManager* GetTextureManager();
|
||||
```
|
||||
|
||||
### IRenderContext
|
||||
|
||||
```cpp
|
||||
class IRenderContext {
|
||||
public:
|
||||
virtual ~IRenderContext() = default;
|
||||
virtual void Clear(float r, float g, float b, float a) = 0;
|
||||
virtual void ClearDepth(float depth) = 0;
|
||||
virtual void SetViewport(int x, int y, int w, int h) = 0;
|
||||
virtual uintptr_t CreateShaderProgram() = 0;
|
||||
virtual uintptr_t GetShaderProgram() const = 0;
|
||||
virtual void InitializeGLState() = 0;
|
||||
};
|
||||
```
|
||||
|
||||
### ISpriteRenderer
|
||||
|
||||
```cpp
|
||||
class ISpriteRenderer {
|
||||
public:
|
||||
virtual ~ISpriteRenderer() = default;
|
||||
virtual void SetColor(float r, float g, float b, float a) = 0;
|
||||
virtual void SetWindowSize(int w, int h) = 0;
|
||||
virtual void RenderImmidiate(uintptr_t textureId, const float uvVertex[8]) const = 0;
|
||||
virtual bool IsHit(float px, float py) const = 0;
|
||||
virtual void ResetRect(float x, float y, float w, float h) = 0;
|
||||
virtual uintptr_t GetTextureId() const = 0;
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 触摸事件映射
|
||||
|
||||
LApp 不依赖任何窗口事件系统,触摸由应用层主动调用:
|
||||
|
||||
```cpp
|
||||
// 对应 QMouseEvent / SDL_MouseButtonEvent / GLFW 回调
|
||||
LAppDelegate::GetInstance()->GetView()->OnTouchesBegan(x, y); // 按下
|
||||
LAppDelegate::GetInstance()->GetView()->OnTouchesMoved(x, y); // 移动
|
||||
LAppDelegate::GetInstance()->GetView()->OnTouchesEnded(x, y); // 释放
|
||||
|
||||
// 坐标需为窗口内像素坐标,原点在左上角
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 项目结构
|
||||
|
||||
```
|
||||
LAppLive2D/
|
||||
├── Inc/
|
||||
│ ├── LAppDelegate.hpp ← 应用入口(单例)
|
||||
│ ├── LAppView.hpp ← 渲染视图管理
|
||||
│ ├── LAppModel.hpp ← 模型实例
|
||||
│ ├── LAppSprite.hpp ← Sprite 绘制(继承 ISpriteRenderer)
|
||||
│ ├── LAppLive2DManager.hpp ← 模型集管理
|
||||
│ ├── LAppTextureManager.hpp ← 纹理管理
|
||||
│ ├── LAppPal.hpp ← 平台抽象(文件IO、时间)
|
||||
│ ├── LAppAllocator.hpp ← 内存分配器
|
||||
│ ├── LAppDefine.hpp ← 配置常量
|
||||
│ ├── LAppWavFileHandler.hpp ← WAV文件解析
|
||||
│ ├── TouchManager.hpp ← 触摸状态管理
|
||||
│ ├── LAppOpenGL.hpp ← OpenGL 头文件 + 后端宏
|
||||
│ │
|
||||
│ ├── IRenderContext.hpp ← 渲染上下文抽象接口 ★
|
||||
│ ├── ISpriteRenderer.hpp ← Sprite渲染抽象接口 ★
|
||||
│ └── GLRenderContext.hpp ← OpenGL IRenderContext 实现 ★
|
||||
│
|
||||
├── Src/
|
||||
│ ├── *.cpp ← 各模块实现
|
||||
│ └── ...
|
||||
│
|
||||
├── CMakeLists.txt ← 子项目构建脚本
|
||||
└── README.md ← 本文件
|
||||
```
|
||||
+41
-72
@@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
#include "LAppDelegate.hpp"
|
||||
// #include <QWidget> // [Misaki] LApp 已完全解耦Qt,不再需要
|
||||
#include <iostream>
|
||||
#include "LAppView.hpp"
|
||||
#include "LAppPal.hpp"
|
||||
@@ -114,20 +115,23 @@ void LAppDelegate::ReleaseInstance()
|
||||
// return GL_TRUE;
|
||||
// }
|
||||
|
||||
bool LAppDelegate::Initialize(GLCore* window)
|
||||
// bool LAppDelegate::Initialize(GLCore* window) // [Misaki] 原
|
||||
// bool LAppDelegate::Initialize(QWidget* window) // [Misaki] 中间解耦版本
|
||||
bool LAppDelegate::Initialize(int windowWidth, int windowHeight) // [Misaki] 完全解耦Qt
|
||||
{
|
||||
if (DebugLogEnable) LAppPal::PrintLogLn("START");
|
||||
_window = window;
|
||||
if (!_window) return false;
|
||||
|
||||
_windowWidth = _window->width();
|
||||
_windowHeight = _window->height();
|
||||
// _window = window; // [Misaki] 不再持有窗口指针
|
||||
// if (!_window) return false;
|
||||
_windowWidth = windowWidth;
|
||||
_windowHeight = windowHeight;
|
||||
|
||||
// OpenGL 初始化(不依赖 glew)
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
// [Misaki] 原代码:原始GL调用,已抽象到IRenderContext
|
||||
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
// glEnable(GL_BLEND);
|
||||
// glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
_renderContext->InitializeGLState();
|
||||
|
||||
_view->Initialize();
|
||||
InitializeCubism();
|
||||
@@ -201,20 +205,22 @@ void LAppDelegate::resize(int width, int height)
|
||||
{
|
||||
if ((_windowWidth != width || _windowHeight != height) && width > 0 && height > 0)
|
||||
{
|
||||
// [Misaki] 先更新尺寸再调_view方法,因为_view内部会通过GetWindowWidth/Height获取
|
||||
_windowWidth = width;
|
||||
_windowHeight = height;
|
||||
//AppViewの初期化
|
||||
_view->Initialize();
|
||||
// スプライトサイズを再設定
|
||||
_view->ResizeSprite();
|
||||
// サイズを保存しておく
|
||||
_windowWidth = width;
|
||||
_windowHeight = height;
|
||||
|
||||
// ビューポート変更
|
||||
glViewport(0, 0, width, height);
|
||||
// glViewport(0, 0, width, height); // [Misaki] 原始GL,改用IRenderContext
|
||||
_renderContext->SetViewport(0, 0, width, height);
|
||||
}
|
||||
else
|
||||
{
|
||||
glViewport(0, 0, width, height);
|
||||
// glViewport(0, 0, width, height); // [Misaki] 原始GL,改用IRenderContext
|
||||
_renderContext->SetViewport(0, 0, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -235,15 +241,18 @@ void LAppDelegate::resize(int width, int height)
|
||||
void LAppDelegate::update()
|
||||
{
|
||||
LAppPal::UpdateTime();
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
LAPP_GL_CLEAR_DEPTH(1.0f);
|
||||
// [Misaki] 原代码:原始GL调用,已抽象到IRenderContext
|
||||
// glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
// LAPP_GL_CLEAR_DEPTH(1.0f);
|
||||
_renderContext->Clear(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
_renderContext->ClearDepth(1.0f);
|
||||
_view->Render();
|
||||
}
|
||||
|
||||
LAppDelegate::LAppDelegate():
|
||||
_cubismOption(),
|
||||
_window(nullptr),
|
||||
// _window(nullptr), // [Misaki] 已解耦,不再持有窗口指针
|
||||
_captured(false),
|
||||
_mouseX(0.0f),
|
||||
_mouseY(0.0f),
|
||||
@@ -384,66 +393,26 @@ void LAppDelegate::OnMouseCallBack(double x, double y)
|
||||
// return programId;
|
||||
// }
|
||||
GLuint LAppDelegate::CreateShader()
|
||||
{
|
||||
// [Misaki] Shader编译逻辑已移入GLRenderContext::CompileShader()
|
||||
// 本函数保留兼容签名,内部委托给IRenderContext
|
||||
return static_cast<GLuint>(_renderContext->GetShaderProgram());
|
||||
}
|
||||
/*
|
||||
// [Misaki] 原Shader编译代码,已迁移至GLRenderContext::CompileShader()
|
||||
GLuint LAppDelegate::CreateShader()
|
||||
{
|
||||
#if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_ES_3) || defined(EMBEDDED_LINUX)
|
||||
// OpenGL ES 2.0/3.0 着色器
|
||||
const char* vertexShader =
|
||||
"#version 100\n"
|
||||
"attribute vec3 position;\n"
|
||||
"attribute vec2 uv;\n"
|
||||
"varying vec2 vuv;\n"
|
||||
"void main() {\n"
|
||||
" gl_Position = vec4(position, 1.0);\n"
|
||||
" vuv = uv;\n"
|
||||
"}\n";
|
||||
const char* fragmentShader =
|
||||
"#version 100\n"
|
||||
"precision mediump float;\n"
|
||||
"varying vec2 vuv;\n"
|
||||
"uniform sampler2D texture;\n"
|
||||
"uniform vec4 baseColor;\n"
|
||||
"void main() {\n"
|
||||
" gl_FragColor = texture2D(texture, vuv) * baseColor;\n"
|
||||
"}\n";
|
||||
const char* vertexShader = ...;
|
||||
...
|
||||
#else
|
||||
// 桌面 OpenGL 2.1 着色器
|
||||
const char* vertexShader =
|
||||
"#version 120\n"
|
||||
"attribute vec3 position;"
|
||||
"attribute vec2 uv;"
|
||||
"varying vec2 vuv;"
|
||||
"void main(void){"
|
||||
" gl_Position = vec4(position, 1.0);"
|
||||
" vuv = uv;"
|
||||
"}";
|
||||
const char* fragmentShader =
|
||||
"#version 120\n"
|
||||
"varying vec2 vuv;"
|
||||
"uniform sampler2D texture;"
|
||||
"uniform vec4 baseColor;"
|
||||
"void main(void){"
|
||||
" gl_FragColor = texture2D(texture, vuv) * baseColor;"
|
||||
"}";
|
||||
...
|
||||
#endif
|
||||
|
||||
// 编译链接着色器(原样)
|
||||
GLuint vertexShaderId = glCreateShader(GL_VERTEX_SHADER);
|
||||
glShaderSource(vertexShaderId, 1, &vertexShader, nullptr);
|
||||
glCompileShader(vertexShaderId);
|
||||
if (!CheckShader(vertexShaderId)) return 0;
|
||||
|
||||
GLuint fragmentShaderId = glCreateShader(GL_FRAGMENT_SHADER);
|
||||
glShaderSource(fragmentShaderId, 1, &fragmentShader, nullptr);
|
||||
glCompileShader(fragmentShaderId);
|
||||
if (!CheckShader(fragmentShaderId)) return 0;
|
||||
|
||||
GLuint programId = glCreateProgram();
|
||||
glAttachShader(programId, vertexShaderId);
|
||||
glAttachShader(programId, fragmentShaderId);
|
||||
glLinkProgram(programId);
|
||||
glUseProgram(programId);
|
||||
...
|
||||
return programId;
|
||||
}
|
||||
*/
|
||||
|
||||
// 鼠标回调简化(不再依赖 GLFWwindow*)
|
||||
void LAppDelegate::OnMouseCallBack(int button, int action, int mods)
|
||||
|
||||
+17
-17
@@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
#include "LAppLive2DManager.hpp"
|
||||
// #include <QWidget> // [Misaki] LApp 已完全解耦Qt
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#if defined(_WIN32)
|
||||
@@ -221,8 +222,8 @@ void LAppLive2DManager::OnUpdate() const
|
||||
{
|
||||
//glfwGetWindowSize(LAppDelegate::GetInstance()->GetWindow(), &width, &height);
|
||||
|
||||
int width = LAppDelegate::GetInstance()->GetWindow()->width();
|
||||
int height = LAppDelegate::GetInstance()->GetWindow()->height();
|
||||
int width = LAppDelegate::GetInstance()->GetWindowWidth();
|
||||
int height = LAppDelegate::GetInstance()->GetWindowHeight();
|
||||
|
||||
csmUint32 modelCount = _models.GetSize();
|
||||
for (csmUint32 i = 0; i < modelCount; ++i)
|
||||
@@ -263,17 +264,16 @@ void LAppLive2DManager::OnUpdate() const
|
||||
LAppDelegate::GetInstance()->GetView()->PostModelDraw(*model);
|
||||
}
|
||||
}
|
||||
#include <AppContext.h>
|
||||
// #include <AppContext.h> // [Misaki] 解耦,改用LAppDelegate回调
|
||||
void LAppLive2DManager::ModelSizeChange(const int Sacle = 15)
|
||||
{
|
||||
// 加载完后根据模型大小来重新设置当前窗口大小
|
||||
const int width = static_cast<int>(_models[0]->GetModel()->GetCanvasWidthPixel() / Sacle);
|
||||
const int height = static_cast<int>(_models[0]->GetModel()->GetCanvasHeightPixel() / Sacle);
|
||||
|
||||
// 确保在主线程调用 UI 相关操作
|
||||
if(AppContext::GetGLCore()) {
|
||||
AppContext::GetGLCore()->setWindowSize(width, height);
|
||||
}
|
||||
// if(AppContext::GetGLCore()) { // [Misaki] 原
|
||||
// AppContext::GetGLCore()->setWindowSize(width, height);
|
||||
// }
|
||||
LAppDelegate::GetInstance()->NotifyWindowResize(width, height); // [Misaki] 通过回调通知应用层
|
||||
LAppPal::PrintLogLn("[APP]窗口尺寸重新设置为: W: %d H: %d", width, height);
|
||||
}
|
||||
void LAppLive2DManager::LoadModelFromPath(const std::string& modelPath, const std::string& fileName)
|
||||
@@ -288,7 +288,8 @@ void LAppLive2DManager::LoadModelFromPath(const std::string& modelPath, const st
|
||||
// 加载完后根据模型大小来重新设置当前窗口大小
|
||||
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); // 获取GLCore上下文
|
||||
// AppContext::GetGLCore()->setWindowSize(width, height); // [Misaki] 原
|
||||
LAppDelegate::GetInstance()->NotifyWindowResize(width, height); // [Misaki] 通过回调通知应用层
|
||||
LAppPal::PrintLogLn("[APP]窗口尺寸重新设置为: W: %d H: %d", width, height);
|
||||
/*
|
||||
* 提供一个半透明表示模型的示例。
|
||||
@@ -351,14 +352,13 @@ void LAppLive2DManager::MountLoadedModel(LAppModel* model)
|
||||
}
|
||||
|
||||
// 加载完后根据模型大小来重新设置当前窗口大小
|
||||
const int width = static_cast<int>(_models[0]->GetModel()->GetCanvasWidthPixel() / 15.0);
|
||||
const int height = static_cast<int>(_models[0]->GetModel()->GetCanvasHeightPixel() / 15.0);
|
||||
|
||||
// 确保在主线程调用 UI 相关操作
|
||||
if(AppContext::GetGLCore()) {
|
||||
AppContext::GetGLCore()->setWindowSize(width, height);
|
||||
}
|
||||
LAppPal::PrintLogLn("[APP]窗口尺寸重新设置为: W: %d H: %d", width, height);
|
||||
// [Misaki] 原代码直接调AppContext,改为统一使用ModelSizeChange
|
||||
// const int width = static_cast<int>(_models[0]->GetModel()->GetCanvasWidthPixel() / 15.0);
|
||||
// const int height = static_cast<int>(_models[0]->GetModel()->GetCanvasHeightPixel() / 15.0);
|
||||
// if(AppContext::GetGLCore()) {
|
||||
// AppContext::GetGLCore()->setWindowSize(width, height);
|
||||
// }
|
||||
ModelSizeChange(15); // [Misaki] 统一入口,回调通知应用层
|
||||
|
||||
// 设置渲染目标等
|
||||
{
|
||||
|
||||
+12
-6
@@ -789,7 +789,8 @@ void LAppModel::DoDraw()
|
||||
return;
|
||||
}
|
||||
|
||||
GetRenderer<Rendering::CubismRenderer_OpenGLES2>()->DrawModel();
|
||||
// GetRenderer<Rendering::CubismRenderer_OpenGLES2>()->DrawModel();
|
||||
GetRenderer<CUBISM_RENDERER_TYPE>()->DrawModel(); // 适配不同渲染器
|
||||
}
|
||||
|
||||
void LAppModel::Draw(CubismMatrix44& matrix)
|
||||
@@ -801,8 +802,10 @@ void LAppModel::Draw(CubismMatrix44& matrix)
|
||||
|
||||
matrix.MultiplyByMatrix(_modelMatrix);
|
||||
|
||||
GetRenderer<Rendering::CubismRenderer_OpenGLES2>()->SetMvpMatrix(&matrix);
|
||||
|
||||
// 設定MVP行列
|
||||
// GetRenderer<Rendering::CubismRenderer_OpenGLES2>()->SetMvpMatrix(&matrix);
|
||||
GetRenderer<CUBISM_RENDERER_TYPE>()->SetMvpMatrix(&matrix); // 适配不同渲染器
|
||||
// 描画
|
||||
DoDraw();
|
||||
}
|
||||
|
||||
@@ -892,13 +895,16 @@ void LAppModel::SetupTextures()
|
||||
const csmInt32 glTextueNumber = texture->id;
|
||||
|
||||
//OpenGL
|
||||
GetRenderer<Rendering::CubismRenderer_OpenGLES2>()->BindTexture(modelTextureNumber, glTextueNumber);
|
||||
// GetRenderer<Rendering::CubismRenderer_OpenGLES2>()->BindTexture(modelTextureNumber, glTextueNumber);
|
||||
GetRenderer<CUBISM_RENDERER_TYPE>()->BindTexture(modelTextureNumber, glTextueNumber); // 适配不同渲染器
|
||||
}
|
||||
|
||||
#ifdef PREMULTIPLIED_ALPHA_ENABLE
|
||||
GetRenderer<Rendering::CubismRenderer_OpenGLES2>()->IsPremultipliedAlpha(true);
|
||||
// GetRenderer<Rendering::CubismRenderer_OpenGLES2>()->IsPremultipliedAlpha(true);
|
||||
GetRenderer<CUBISM_RENDERER_TYPE>()->IsPremultipliedAlpha(true);
|
||||
#else
|
||||
GetRenderer<Rendering::CubismRenderer_OpenGLES2>()->IsPremultipliedAlpha(false);
|
||||
// GetRenderer<Rendering::CubismRenderer_OpenGLES2>()->IsPremultipliedAlpha(false);
|
||||
GetRenderer<CUBISM_RENDERER_TYPE>()->IsPremultipliedAlpha(false);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
+17
-9
@@ -7,7 +7,8 @@
|
||||
|
||||
#include "LAppSprite.hpp"
|
||||
|
||||
LAppSprite::LAppSprite(float x, float y, float width, float height, GLuint textureId, GLuint programId)
|
||||
// LAppSprite::LAppSprite(float x, float y, float width, float height, GLuint textureId, GLuint programId) // [Misaki] 原
|
||||
LAppSprite::LAppSprite(float x, float y, float width, float height, uintptr_t textureId, uintptr_t programId) // [Misaki] 抽象类型
|
||||
: _rect()
|
||||
{
|
||||
_rect.left = (x - width * 0.5f);
|
||||
@@ -16,11 +17,15 @@ LAppSprite::LAppSprite(float x, float y, float width, float height, GLuint textu
|
||||
_rect.down = (y - height * 0.5f);
|
||||
_textureId = textureId;
|
||||
|
||||
// 何番目のattribute変数か
|
||||
_positionLocation = glGetAttribLocation(programId, "position");
|
||||
_uvLocation = glGetAttribLocation(programId, "uv");
|
||||
_textureLocation = glGetUniformLocation(programId, "texture");
|
||||
_colorLocation = glGetUniformLocation(programId, "baseColor");
|
||||
// [Misaki] 原代码:直接传GLuint,改用static_cast适配抽象类型uintptr_t
|
||||
// _positionLocation = glGetAttribLocation(programId, "position");
|
||||
// _uvLocation = glGetAttribLocation(programId, "uv");
|
||||
// _textureLocation = glGetUniformLocation(programId, "texture");
|
||||
// _colorLocation = glGetUniformLocation(programId, "baseColor");
|
||||
_positionLocation = glGetAttribLocation(static_cast<GLuint>(programId), "position");
|
||||
_uvLocation = glGetAttribLocation(static_cast<GLuint>(programId), "uv");
|
||||
_textureLocation = glGetUniformLocation(static_cast<GLuint>(programId), "texture");
|
||||
_colorLocation = glGetUniformLocation(static_cast<GLuint>(programId), "baseColor");
|
||||
|
||||
_spriteColor[0] = 1.0f;
|
||||
_spriteColor[1] = 1.0f;
|
||||
@@ -72,11 +77,13 @@ void LAppSprite::Render() const
|
||||
|
||||
|
||||
// モデルの描画
|
||||
glBindTexture(GL_TEXTURE_2D, _textureId);
|
||||
// glBindTexture(GL_TEXTURE_2D, _textureId); // [Misaki] 原
|
||||
glBindTexture(GL_TEXTURE_2D, static_cast<GLuint>(_textureId)); // [Misaki] 抽象类型转换
|
||||
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
||||
}
|
||||
|
||||
void LAppSprite::RenderImmidiate(GLuint textureId, const GLfloat uvVertex[8]) const
|
||||
// void LAppSprite::RenderImmidiate(GLuint textureId, const GLfloat uvVertex[8]) const // [Misaki] 原
|
||||
void LAppSprite::RenderImmidiate(uintptr_t textureId, const float uvVertex[8]) const // [Misaki] 抽象类型
|
||||
{
|
||||
if (_maxWidth == 0 || _maxHeight == 0)
|
||||
{
|
||||
@@ -106,7 +113,8 @@ void LAppSprite::RenderImmidiate(GLuint textureId, const GLfloat uvVertex[8]) co
|
||||
glUniform4f(_colorLocation, _spriteColor[0], _spriteColor[1], _spriteColor[2], _spriteColor[3]);
|
||||
|
||||
// モデルの描画
|
||||
glBindTexture(GL_TEXTURE_2D, textureId);
|
||||
// glBindTexture(GL_TEXTURE_2D, textureId); // [Misaki] 原
|
||||
glBindTexture(GL_TEXTURE_2D, static_cast<GLuint>(textureId)); // [Misaki] 抽象类型转换
|
||||
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
||||
}
|
||||
|
||||
|
||||
+22
-13
@@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
#include "LAppView.hpp"
|
||||
// #include <QWidget> // [Misaki] 已完全解耦Qt,改用GetWindowWidth/Height
|
||||
#include <math.h>
|
||||
#include <string>
|
||||
#include "LAppPal.hpp"
|
||||
@@ -60,8 +61,8 @@ void LAppView::Initialize()
|
||||
{
|
||||
int width, height;
|
||||
//glfwGetWindowSize(LAppDelegate::GetInstance()->GetWindow(), &width, &height);
|
||||
width = LAppDelegate::GetInstance()->GetWindow()->width();
|
||||
height = LAppDelegate::GetInstance()->GetWindow()->height();
|
||||
width = LAppDelegate::GetInstance()->GetWindowWidth();
|
||||
height = LAppDelegate::GetInstance()->GetWindowHeight();
|
||||
|
||||
if(width==0 || height==0)
|
||||
{
|
||||
@@ -109,8 +110,8 @@ void LAppView::Render()
|
||||
// 画面サイズを取得する
|
||||
int maxWidth, maxHeight;
|
||||
//glfwGetWindowSize(LAppDelegate::GetInstance()->GetWindow(), &maxWidth, &maxHeight);
|
||||
maxWidth = LAppDelegate::GetInstance()->GetWindow()->width();
|
||||
maxHeight = LAppDelegate::GetInstance()->GetWindow()->height();
|
||||
maxWidth = LAppDelegate::GetInstance()->GetWindowWidth();
|
||||
maxHeight = LAppDelegate::GetInstance()->GetWindowHeight();
|
||||
|
||||
//_back->SetWindowSize(maxWidth, maxHeight);
|
||||
//_gear->SetWindowSize(maxWidth, maxHeight);
|
||||
@@ -155,12 +156,13 @@ void LAppView::Render()
|
||||
|
||||
void LAppView::InitializeSprite()
|
||||
{
|
||||
_programId = LAppDelegate::GetInstance()->CreateShader();
|
||||
// _programId = LAppDelegate::GetInstance()->CreateShader();
|
||||
_programId = LAppDelegate::GetInstance()->GetRenderContext()->CreateShaderProgram();
|
||||
|
||||
int width, height;
|
||||
//glfwGetWindowSize(LAppDelegate::GetInstance()->GetWindow(), &width, &height);
|
||||
width = LAppDelegate::GetInstance()->GetWindow()->width();
|
||||
height = LAppDelegate::GetInstance()->GetWindow()->height();
|
||||
width = LAppDelegate::GetInstance()->GetWindowWidth();
|
||||
height = LAppDelegate::GetInstance()->GetWindowHeight();
|
||||
|
||||
LAppTextureManager* textureManager = LAppDelegate::GetInstance()->GetTextureManager();
|
||||
const string resourcesPath = ResourcesPath;
|
||||
@@ -196,6 +198,13 @@ void LAppView::InitializeSprite()
|
||||
// x = width * 0.5f;
|
||||
// y = height * 0.5f;
|
||||
// _renderSprite = new LAppSprite(x, y, static_cast<float>(width), static_cast<float>(height), 0, _programId);
|
||||
// [Misaki] _programId 类型由GLuint改为uintptr_t,构造参数匹配
|
||||
// _renderSprite = new LAppSprite(x, y, static_cast<float>(width),
|
||||
// static_cast<float>(height), 0,
|
||||
// static_cast<GLuint>(_programId));
|
||||
float x = width * 0.5f;
|
||||
float y = height * 0.5f;
|
||||
_renderSprite = new LAppSprite(x, y, static_cast<float>(width), static_cast<float>(height), 0, static_cast<uintptr_t>(_programId));
|
||||
}
|
||||
|
||||
void LAppView::OnTouchesBegan(float px, float py) const
|
||||
@@ -303,8 +312,8 @@ void LAppView::PreModelDraw(LAppModel& refModel)
|
||||
{// 描画ターゲット内部未作成の場合はここで作成
|
||||
int width, height;
|
||||
/*glfwGetWindowSize(LAppDelegate::GetInstance()->GetWindow(), &width, &height);*/
|
||||
width = LAppDelegate::GetInstance()->GetWindow()->width();
|
||||
height = LAppDelegate::GetInstance()->GetWindow()->height();
|
||||
width = LAppDelegate::GetInstance()->GetWindowWidth();
|
||||
height = LAppDelegate::GetInstance()->GetWindowHeight();
|
||||
|
||||
if (width != 0 && height != 0)
|
||||
{
|
||||
@@ -350,8 +359,8 @@ void LAppView::PostModelDraw(LAppModel& refModel)
|
||||
int maxWidth, maxHeight;
|
||||
/*glfwGetWindowSize(LAppDelegate::GetInstance()->GetWindow(), &maxWidth, &maxHeight);*/
|
||||
|
||||
maxWidth = LAppDelegate::GetInstance()->GetWindow()->width(); // Misaki 修改
|
||||
maxHeight = LAppDelegate::GetInstance()->GetWindow()->height();
|
||||
maxWidth = LAppDelegate::GetInstance()->GetWindowWidth(); // Misaki 修改
|
||||
maxHeight = LAppDelegate::GetInstance()->GetWindowHeight();
|
||||
|
||||
_renderSprite->SetWindowSize(maxWidth, maxHeight);
|
||||
|
||||
@@ -400,8 +409,8 @@ void LAppView::ResizeSprite()
|
||||
// 描画領域サイズ
|
||||
int width, height;
|
||||
//glfwGetWindowSize(LAppDelegate::GetInstance()->GetWindow(), &width, &height);
|
||||
width = LAppDelegate::GetInstance()->GetWindow()->width();
|
||||
height = LAppDelegate::GetInstance()->GetWindow()->height();
|
||||
width = LAppDelegate::GetInstance()->GetWindowWidth();
|
||||
height = LAppDelegate::GetInstance()->GetWindowHeight();
|
||||
|
||||
float x = 0.0f;
|
||||
float y = 0.0f;
|
||||
|
||||
+29
-32
@@ -39,6 +39,13 @@ else()
|
||||
message(FATAL_ERROR "Unsupported platform")
|
||||
endif()
|
||||
|
||||
# 渲染后端选择
|
||||
if(PLAT STREQUAL "linux_arm")
|
||||
add_definitions(-DRENDER_BACKEND_GLES2)
|
||||
else()
|
||||
add_definitions(-DRENDER_BACKEND_OPENGL)
|
||||
endif()
|
||||
|
||||
message(STATUS " 当前Qt路径: ${CMAKE_PREFIX_PATH}")
|
||||
message(STATUS " 当前平台: ${PLAT}, 架构: ${ARCH}")
|
||||
|
||||
@@ -51,11 +58,6 @@ endif()
|
||||
set(FRAMEWORK_SOURCE OpenGL)
|
||||
|
||||
# 查找源文件
|
||||
file(GLOB_RECURSE LAppLive2D
|
||||
CONFIGURE_DEPENDS
|
||||
"3rdparty/Live2D/Src/LAppLive2D/Src/*.cpp"
|
||||
"3rdparty/Live2D/Src/LAppLive2D/Inc/*.hpp"
|
||||
)
|
||||
file(GLOB_RECURSE YosugaSrc
|
||||
CONFIGURE_DEPENDS
|
||||
"src/Handle/AudioHandle/Src/*.cpp"
|
||||
@@ -119,7 +121,7 @@ else()
|
||||
endif()
|
||||
|
||||
# 主可执行文件
|
||||
add_executable(${PROJECT_NAME} main.cpp ${LAppLive2D} ${YosugaSrc})
|
||||
add_executable(${PROJECT_NAME} main.cpp ${YosugaSrc})
|
||||
|
||||
# =============================================
|
||||
# 库导入路径配置
|
||||
@@ -168,6 +170,25 @@ add_library(Live2DCubismCore STATIC IMPORTED GLOBAL)
|
||||
set_target_properties(Live2DCubismCore PROPERTIES IMPORTED_LOCATION "${CORE_LIB_PATH}")
|
||||
message(STATUS "Live2D Core 库: ${CORE_LIB_PATH}")
|
||||
|
||||
# 导入 LAppLive2D 子项目 Live2D 应用层,静态库
|
||||
# 依赖顺序:lapp_live2d -> Framework -> Live2DCubismCore
|
||||
add_subdirectory(3rdparty/Live2D/Src/LAppLive2D)
|
||||
|
||||
# LAppOpenGL.hpp 根据平台选择 GL / GLES2 头文件,为 lapp_live2d 补充对应路径
|
||||
if(NOT PLAT STREQUAL "linux_arm")
|
||||
target_include_directories(lapp_live2d PUBLIC
|
||||
3rdparty/Live2D/Src/glew/include
|
||||
3rdparty/Live2D/Src/glew/include/GL
|
||||
3rdparty/Live2D/Src/glfw/include
|
||||
3rdparty/Live2D/Src/glfw/include/GLFW
|
||||
)
|
||||
else()
|
||||
target_include_directories(lapp_live2d PUBLIC
|
||||
/home/misaki/MisakiCodes/Env/rk3566-sdk/host/aarch64-buildroot-linux-gnu/sysroot/usr/include
|
||||
/home/misaki/MisakiCodes/Env/rk3566-sdk/host/aarch64-buildroot-linux-gnu/sysroot/usr/include/GLES2
|
||||
)
|
||||
endif()
|
||||
|
||||
# GLFW 和 GLEW(仅桌面平台需要)
|
||||
if(NOT PLAT STREQUAL "linux_arm")
|
||||
# glfw
|
||||
@@ -194,11 +215,10 @@ if(NOT PLAT STREQUAL "linux_arm")
|
||||
message(STATUS "GLEW 库: ${GLEW_LIB_NAME}")
|
||||
endif()
|
||||
|
||||
# =============================================
|
||||
# 链接库
|
||||
# =============================================
|
||||
if(PLAT STREQUAL "linux_arm") ## 针对嵌入式Linux的配置,部分条目需要根据你的soc以及sysroot进行修改
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE
|
||||
lapp_live2d
|
||||
Framework
|
||||
Live2DCubismCore
|
||||
# Mali GPU 驱动完整链接(EGLFS 必需)
|
||||
@@ -217,6 +237,7 @@ if(PLAT STREQUAL "linux_arm") ## 针对嵌入式Linux的配置,部分条
|
||||
else()
|
||||
# 桌面平台
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE
|
||||
lapp_live2d
|
||||
Framework
|
||||
glfw3
|
||||
GLEW
|
||||
@@ -238,14 +259,8 @@ else()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# =============================================
|
||||
# 头文件路径
|
||||
# =============================================
|
||||
target_include_directories(${PROJECT_NAME} PRIVATE
|
||||
3rdparty/Live2D/Src/Framework/src
|
||||
3rdparty/Live2D/Src/Core/include
|
||||
3rdparty/Live2D/Src/stb
|
||||
3rdparty/Live2D/Src/LAppLive2D/Inc
|
||||
3rdparty/autogui-cpp/src
|
||||
src/Handle/AudioHandle/Inc
|
||||
src/Handle/NetWorkHandle/Inc
|
||||
@@ -258,24 +273,6 @@ target_include_directories(${PROJECT_NAME} PRIVATE
|
||||
src/Utils/Inc
|
||||
)
|
||||
|
||||
# ARM 平台需要包含 sysroot 中的 OpenGL ES 头文件 此处需要根据实际sysroot目录进行修改配置
|
||||
if(PLAT STREQUAL "linux_arm")
|
||||
target_include_directories(${PROJECT_NAME} PRIVATE
|
||||
/home/misaki/MisakiCodes/Env/rk3566-sdk/host/aarch64-buildroot-linux-gnu/sysroot/usr/include
|
||||
/home/misaki/MisakiCodes/Env/rk3566-sdk/host/aarch64-buildroot-linux-gnu/sysroot/usr/include/GLES2
|
||||
)
|
||||
endif()
|
||||
|
||||
# 非 ARM 平台才需要 GLEW/GLFW 头文件路径
|
||||
if(NOT PLAT STREQUAL "linux_arm")
|
||||
target_include_directories(${PROJECT_NAME} PRIVATE
|
||||
3rdparty/Live2D/Src/glew/include
|
||||
3rdparty/Live2D/Src/glew/include/GL
|
||||
3rdparty/Live2D/Src/glfw/include
|
||||
3rdparty/Live2D/Src/glfw/include/GLFW
|
||||
)
|
||||
endif()
|
||||
|
||||
# 资源复制(所有平台)
|
||||
file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/other/Resources"
|
||||
DESTINATION "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
|
||||
+11
-1
@@ -15,6 +15,7 @@
|
||||
|
||||
#include "TextRenderer.h"
|
||||
#include "AppContext.h"
|
||||
#include "GLRenderContext.hpp" // 渲染后端抽象
|
||||
#ifdef EMBEDDED_LINUX
|
||||
#include "AppCore.h"
|
||||
#include <QIcon>
|
||||
@@ -337,7 +338,16 @@ void GLCore::mouseReleaseEvent(QMouseEvent* event)
|
||||
|
||||
void GLCore::initializeGL()
|
||||
{
|
||||
LAppDelegate::GetInstance()->Initialize(this);
|
||||
// [Misaki] 注入渲染后端抽象层,由GLCore(OpenGL)创建GLRenderContext并交给LAppDelegate管理
|
||||
if (!LAppDelegate::GetInstance()->GetRenderContext()) {
|
||||
LAppDelegate::GetInstance()->SetRenderContext(new GLRenderContext());
|
||||
}
|
||||
// [Misaki] 注册窗口大小变更回调 — 模型加载后通过此回调通知GLCore调整窗口
|
||||
LAppDelegate::GetInstance()->SetWindowResizeCallback([this](int w, int h) {
|
||||
setWindowSize(w, h);
|
||||
});
|
||||
// LAppDelegate::GetInstance()->Initialize(this); // [Misaki] 原(QWidget*)
|
||||
LAppDelegate::GetInstance()->Initialize(this->width(), this->height()); // [Misaki] 解耦Qt
|
||||
}
|
||||
|
||||
void GLCore::paintGL()
|
||||
|
||||
Reference in New Issue
Block a user