feat(renderer): Add ModelRender,Camera,TextRenderer
- Add ModelRender - Add Camera - Add TextRenderer - Add RTTI Object class - Add PhysicsCollider interface: getClassName method - Add AlignedMemoryStack class - fix Logger and LoggerSpdLog - fix Model2D method: getPhysics, remove const qualifier
This commit is contained in:
2
Vivid2DRenderer/AlignedMemoryStack.cpp
Normal file
2
Vivid2DRenderer/AlignedMemoryStack.cpp
Normal file
@@ -0,0 +1,2 @@
|
||||
#include "pch.h"
|
||||
#include "AlignedMemoryStack.h"
|
||||
53
Vivid2DRenderer/AlignedMemoryStack.h
Normal file
53
Vivid2DRenderer/AlignedMemoryStack.h
Normal file
@@ -0,0 +1,53 @@
|
||||
#pragma once
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <stack>
|
||||
|
||||
class AlignedMemoryStack {
|
||||
char* buffer = nullptr;
|
||||
size_t capacity = 0;
|
||||
size_t offset = 0;
|
||||
std::stack<size_t> markers;
|
||||
|
||||
public:
|
||||
AlignedMemoryStack(size_t initialSize = 64 * 1024) {
|
||||
buffer = new char[initialSize];
|
||||
capacity = initialSize;
|
||||
}
|
||||
|
||||
~AlignedMemoryStack() {
|
||||
delete[] buffer;
|
||||
}
|
||||
|
||||
void* pushStackAlloc(size_t size, size_t align = alignof(std::max_align_t)) {
|
||||
size_t aligned = (offset + align - 1) & ~(align - 1);
|
||||
if (aligned + size > capacity) {
|
||||
// 简单扩容策略:直接翻倍
|
||||
size_t newCapacity = (aligned + size) * 2;
|
||||
char* newBuffer = new char[newCapacity];
|
||||
std::memcpy(newBuffer, buffer, offset);
|
||||
delete[] buffer;
|
||||
buffer = newBuffer;
|
||||
capacity = newCapacity;
|
||||
}
|
||||
void* ptr = buffer + aligned;
|
||||
markers.push(offset);
|
||||
offset = aligned + size;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
template<typename PtrType>
|
||||
PtrType* pushStackAllocate(size_t size, size_t align = alignof(std::max_align_t)) {
|
||||
return pushStackAlloc(size, align);
|
||||
}
|
||||
|
||||
void popStack() {
|
||||
offset = markers.top();
|
||||
markers.pop();
|
||||
}
|
||||
|
||||
void reset() {
|
||||
offset = 0;
|
||||
markers = std::stack<size_t>();
|
||||
}
|
||||
};
|
||||
1048
Vivid2DRenderer/ModelRender.cpp
Normal file
1048
Vivid2DRenderer/ModelRender.cpp
Normal file
File diff suppressed because it is too large
Load Diff
516
Vivid2DRenderer/ModelRender.h
Normal file
516
Vivid2DRenderer/ModelRender.h
Normal file
@@ -0,0 +1,516 @@
|
||||
#pragma once
|
||||
|
||||
#include <Logger.h>
|
||||
#include <glm/vec2.hpp>
|
||||
#include <glm/vec3.hpp>
|
||||
#include <glm/vec4.hpp>
|
||||
#include <glm/mat3x3.hpp>
|
||||
#include <glfw/glfw3.h>
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include "model/Mesh2D.h"
|
||||
#include "systems/sources/ShaderProgram.h"
|
||||
#include "systems/Camera.h"
|
||||
#include "TextRenderer.h"
|
||||
#include "systems/sources/CompleteShader.h"
|
||||
#include "systems/sources/ShaderManagement.h"
|
||||
#include "model/util/LightSource.h"
|
||||
#include "model/Model2D.h"
|
||||
#include "model/util/PhysicsSystem.h"
|
||||
#include "systems/buffer/Tesselator.h"
|
||||
#include "systems/buffer/BufferBuilder.h"
|
||||
|
||||
class IllegalStateException : public std::exception {
|
||||
private:
|
||||
std::string message;
|
||||
public:
|
||||
IllegalStateException(const std::string& msg) {
|
||||
this->message = msg;
|
||||
}
|
||||
char const* what() const noexcept override {
|
||||
return message.c_str();
|
||||
}
|
||||
const std::string& getMessage() const {
|
||||
return message;
|
||||
}
|
||||
operator std::string() const {
|
||||
return message;
|
||||
}
|
||||
};
|
||||
|
||||
// 单例模式
|
||||
class VIVID_2D_MYDLL_API ModelRender {
|
||||
private:
|
||||
explicit ModelRender() = default; // 默认构造函数
|
||||
ModelRender(const ModelRender& other) = delete; // 复制构造函数
|
||||
ModelRender(const ModelRender&& other) = delete; // 移动构造函数
|
||||
~ModelRender() = default; // 默认析构函数
|
||||
|
||||
public:
|
||||
// 获取全局唯一实例
|
||||
static ModelRender* instance() {
|
||||
if (s_instance == nullptr) {
|
||||
s_instance = new ModelRender();
|
||||
}
|
||||
return s_instance;
|
||||
}
|
||||
|
||||
static void destroyInstance() {
|
||||
if (s_instance) {
|
||||
ModelRender* tmp = s_instance;
|
||||
s_instance = nullptr;
|
||||
delete tmp;
|
||||
}
|
||||
}
|
||||
|
||||
// 类型定义
|
||||
typedef glm::vec2 Vector2f;
|
||||
typedef glm::vec3 Vector3f;
|
||||
typedef glm::vec4 Vector4f;
|
||||
typedef glm::mat3 Matrix3f;
|
||||
typedef Vivid2D::Mesh2D Mesh2D;
|
||||
typedef Vivid2D::Model2D Model2D;
|
||||
typedef Vivid2D::util::LightSource LightSource;
|
||||
typedef Vivid2D::util::PhysicsSystem PhysicsSystem;
|
||||
typedef Vivid2D::util::PhysicsParticle PhysicsParticle;
|
||||
typedef Vivid2D::util::CircleCollider CircleCollider;
|
||||
typedef Vivid2D::util::RectangleCollider RectangleCollider;
|
||||
|
||||
typedef Vivid2D::ModelPart ModelPart;
|
||||
typedef Vivid2D::Render::Buffer::Tesselator Tesselator;
|
||||
typedef Vivid2D::Render::Buffer::BufferBuilder BufferBuilder;
|
||||
|
||||
using ByteBuffer = std::vector<unsigned char>;
|
||||
|
||||
/**
|
||||
* 缩略图边界计算结果
|
||||
*/
|
||||
struct ThumbnailBounds {
|
||||
GLfloat minX, maxX, minY, maxY;
|
||||
GLfloat scale;
|
||||
GLfloat offsetX, offsetY;
|
||||
};
|
||||
|
||||
struct MeshGLResources {
|
||||
GLuint vao = 0;
|
||||
GLuint vbo = 0;
|
||||
GLuint ebo = 0;
|
||||
|
||||
void dispose() {
|
||||
if (ebo != 0) {
|
||||
glDeleteBuffers(1, &ebo);
|
||||
ebo = 0;
|
||||
}
|
||||
if (vbo != 0) {
|
||||
glDeleteBuffers(1, &vbo);
|
||||
vbo = 0;
|
||||
}
|
||||
if (vao != 0) {
|
||||
glDeleteVertexArrays(1, &vao);
|
||||
vao = 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
public:
|
||||
// 常量
|
||||
static constexpr double c_pi = 3.14159265358979323846;
|
||||
|
||||
private:
|
||||
Logger logger{ "ModelRender" };
|
||||
// 全局唯一实例
|
||||
static ModelRender* s_instance;
|
||||
bool m_isInitialized = false;
|
||||
struct Size {
|
||||
int width;
|
||||
int height;
|
||||
};
|
||||
/**
|
||||
* 视口大小(宽高)(像素),定义渲染区域的大小
|
||||
* 默认值:(800, 600) (像素)
|
||||
*
|
||||
* @see #setViewport(int, int)
|
||||
* @see #setViewport(Size)
|
||||
*/
|
||||
Size m_viewportSize{ 800, 600 };
|
||||
/**
|
||||
* 清除颜色(RGBA),用于在每帧开始时清空颜色缓冲区
|
||||
* 默认值:黑色不透明 (0.0f, 0.0f, 0.0f, 1.0f)
|
||||
*
|
||||
* @see RenderSystem#clearColor(GLfloat, GLfloat, GLfloat, GLfloat)
|
||||
*/
|
||||
Vector4f m_clearColor{ 0.0f, 0.0f, 0.0f, 1.0f };
|
||||
|
||||
/**
|
||||
* 深度测试启用标志,控制是否进行深度缓冲测试
|
||||
* 在2D渲染中通常禁用以提高性能
|
||||
* 默认值:false(禁用)
|
||||
*
|
||||
* @see RenderSystem#enableDepthTest()
|
||||
* @see RenderSystem#disableDepthTest()
|
||||
*/
|
||||
bool m_enableDepthTest = false;
|
||||
|
||||
/**
|
||||
* 混合功能启用标志,控制透明度和颜色混合
|
||||
* 默认值:true(启用)
|
||||
*
|
||||
* @see RenderSystem#enableBlend()
|
||||
* @see RenderSystem#disableBlend()
|
||||
*/
|
||||
bool m_enableBlending = true;
|
||||
|
||||
/**
|
||||
* 最大光源数量,用于限制同时启用的光源数量
|
||||
* 默认值:80
|
||||
*/
|
||||
int m_maxLightCount = 80;
|
||||
|
||||
// ================== 着色器与资源管理 ==================
|
||||
|
||||
/**
|
||||
* 默认着色器程序,用于大多数模型的渲染
|
||||
* 包含基础的光照、纹理和变换功能
|
||||
*
|
||||
* @see #compileDefaultShader()
|
||||
*/
|
||||
ShaderProgram* m_defaultProgram = nullptr;
|
||||
|
||||
/**
|
||||
* 网格GPU资源缓存,管理已上传到GPU的网格数据
|
||||
* 键:Mesh2D对象
|
||||
* 值:对应的OpenGL资源(VAO、VBO、EBO)
|
||||
*
|
||||
* @see MeshGLResources
|
||||
*/
|
||||
std::unordered_map<Mesh2D, MeshGLResources> m_meshResources;
|
||||
|
||||
/**
|
||||
* 纹理单元分配器,用于管理多个纹理的绑定
|
||||
* 确保不同的纹理绑定到正确的纹理单元
|
||||
* 默认从0开始递增分配
|
||||
*/
|
||||
[[deprecated]]int m_textureUnitAllocator;
|
||||
|
||||
/**
|
||||
* 默认白色纹理ID,当模型没有指定纹理时使用
|
||||
* 这是一个1x1的纯白色纹理,确保模型有基本的颜色显示
|
||||
*
|
||||
* @see #createDefaultTexture()
|
||||
*/
|
||||
int m_defaultTextureId = 0;
|
||||
|
||||
// ================== 碰撞箱渲染配置 ==================
|
||||
|
||||
/**
|
||||
* 碰撞箱渲染开关,控制是否在场景中显示物理碰撞体的轮廓
|
||||
* 调试时非常有用,可以直观看到碰撞边界
|
||||
* 默认值:true(启用)
|
||||
*/
|
||||
bool m_renderColliders = true;
|
||||
|
||||
/**
|
||||
* 碰撞箱线框宽度,控制碰撞体轮廓线的粗细
|
||||
* 单位:像素
|
||||
* 默认值:1.0f
|
||||
*/
|
||||
GLfloat m_colliderLineWidth = 1.0f;
|
||||
|
||||
/**
|
||||
* 碰撞箱颜色(RGBA),定义碰撞体轮廓的显示颜色
|
||||
* 默认值:白色不透明 (1.0f, 1.0f, 1.0f, 1.0f)
|
||||
*/
|
||||
Vector4f m_colliderColor{ 1.0f, 1.0f, 1.0f, 1.0f };
|
||||
|
||||
/**
|
||||
* 圆形碰撞体细分数量,控制圆形碰撞体的平滑度
|
||||
* 值越高圆形越平滑,但渲染开销也越大
|
||||
* 默认值:32(在性能和视觉效果间取得平衡)
|
||||
*/
|
||||
int m_circleSegments = 32;
|
||||
|
||||
/**
|
||||
* 光源位置渲染开关,控制是否在场景中显示光源的位置
|
||||
* 用点状标记显示每个启用的光源位置
|
||||
* 默认值:true(启用)
|
||||
*/
|
||||
bool m_renderLightPositions = true;
|
||||
|
||||
// ================== 摄像机状态 ==================
|
||||
|
||||
/**
|
||||
* 默认摄像机,用于控制场景的视图和缩放
|
||||
* 默认位置:(0, 0)
|
||||
*/
|
||||
Camera m_camera{0, 0};
|
||||
|
||||
// ================== 字体管理 ==================
|
||||
std::unique_ptr<TextRenderer> m_defaultTextRenderer;
|
||||
Size m_fontBitmapSize{ 512, 512 };
|
||||
int m_fontFirstChar = 32;
|
||||
int m_fontCharCount = 96;
|
||||
|
||||
public:
|
||||
// ================== 摄像机API方法 ==================
|
||||
|
||||
/**
|
||||
* 获取摄像机对象副本
|
||||
*/
|
||||
Camera getCamera() const {
|
||||
return m_camera;
|
||||
}
|
||||
/**
|
||||
* 获取当前实例摄像机引用
|
||||
*/
|
||||
Camera& getCameraReference() {
|
||||
return m_camera;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置摄像机位置
|
||||
*/
|
||||
void setCameraPosition(GLfloat x, GLfloat y) {
|
||||
m_camera.setPosition(x, y);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置摄像机缩放
|
||||
*/
|
||||
void setCameraZoom(GLfloat zoom) {
|
||||
m_camera.setZoom(zoom);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置摄像机Z轴位置
|
||||
*/
|
||||
void setCameraZPosition(GLfloat z) {
|
||||
m_camera.setZPosition(z);
|
||||
}
|
||||
|
||||
/**
|
||||
* 移动摄像机
|
||||
*/
|
||||
void moveCamera(GLfloat dx, GLfloat dy) {
|
||||
m_camera.move(dx, dy);
|
||||
}
|
||||
|
||||
/**
|
||||
* 缩放摄像机
|
||||
*/
|
||||
void zoomCamera(GLfloat factor) {
|
||||
m_camera.zoom(factor);
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置摄像机
|
||||
*/
|
||||
void resetCamera() {
|
||||
m_camera.reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* 启用/禁用摄像机
|
||||
*/
|
||||
void setCameraEnabled(bool enabled) {
|
||||
m_camera.setEnabled(enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建考虑摄像机变换的投影矩阵
|
||||
*/
|
||||
Matrix3f buildCameraProjection(int width, int height);
|
||||
|
||||
|
||||
// ================== 初始化 / 清理 ==================
|
||||
void initialize() noexcept(false);
|
||||
|
||||
/**
|
||||
* 初始化所有非默认着色器的基础信息(顶点坐标等)
|
||||
*/
|
||||
void initNonDefaultShaders();
|
||||
|
||||
/**
|
||||
* 初始化着色器的基础uniforms(顶点坐标相关)
|
||||
*/
|
||||
void initShaderBasicUniforms(ShaderProgram* program, CompleteShader* shader);
|
||||
|
||||
|
||||
auto& getTextRenderer() const {
|
||||
return m_defaultTextRenderer;
|
||||
}
|
||||
|
||||
// ================== 工具 ==================
|
||||
static Matrix3f buildOrthoProjection(int width, int height);
|
||||
|
||||
/**
|
||||
* 渲染文字
|
||||
*
|
||||
* @param text 文字内容
|
||||
* @param x 世界坐标 X
|
||||
* @param y 世界坐标 Y ,反转的
|
||||
* @param color RGBA 颜色
|
||||
*/
|
||||
void renderText(std::string text, GLfloat x, GLfloat y, Vector4f color);
|
||||
|
||||
/**
|
||||
* 获取默认摄像机与当前摄像机之间的偏移量
|
||||
*
|
||||
* @return Vector2f 偏移向量 (dx, dy)
|
||||
*/
|
||||
Vector2f getCameraOffset();
|
||||
|
||||
void setViewport(int width, int height);
|
||||
|
||||
// ================== 辅助:外部获取状态 ==================
|
||||
bool isInitialized() const {
|
||||
return m_isInitialized;
|
||||
}
|
||||
|
||||
int getLoadedMeshCount() const {
|
||||
return m_meshResources.size();
|
||||
}
|
||||
|
||||
void cleanup();
|
||||
|
||||
// ================== 渲染流程 (已修改) ==================
|
||||
void render(GLfloat deltaTime, Model2D& model);
|
||||
|
||||
// ================== 缩略图渲染方法 ==================
|
||||
|
||||
/**
|
||||
* 渲染模型缩略图(图层式渲染,不受摄像机控制)
|
||||
*
|
||||
* <p>该方法提供类似PS图层预览的缩略图渲染功能:</p>
|
||||
* <ul>
|
||||
* <li>固定位置和大小,不受摄像机影响</li>
|
||||
* <li>自动缩放确保模型完全可见</li>
|
||||
* <li>禁用复杂效果以提高性能</li>
|
||||
* <li>独立的渲染状态管理</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param model 要渲染的模型
|
||||
* @param x 缩略图左上角X坐标(屏幕坐标)
|
||||
* @param y 缩略图左上角Y坐标(屏幕坐标)
|
||||
* @param width 缩略图宽度
|
||||
* @param height 缩略图高度
|
||||
*/
|
||||
void renderThumbnail(Model2D& model, GLfloat x, GLfloat y, GLfloat width, GLfloat height);
|
||||
|
||||
private:
|
||||
|
||||
void logGLInfo();
|
||||
|
||||
void uploadLightsToShader(ShaderProgram* sp, Model2D& model);
|
||||
|
||||
void setupGLState();
|
||||
|
||||
void compileDefaultShader();
|
||||
|
||||
void createDefaultTexture();
|
||||
|
||||
|
||||
/**
|
||||
* 计算模型的边界和合适的缩放比例
|
||||
*/
|
||||
ThumbnailBounds calculateThumbnailBounds(Model2D& model, GLfloat thumbWidth, GLfloat thumbHeight);
|
||||
|
||||
/**
|
||||
* 递归计算模型的边界
|
||||
*/
|
||||
void calculateModelBounds(Model2D& model, ThumbnailBounds bounds, Matrix3f parentTransform);
|
||||
|
||||
/**
|
||||
* 递归计算部件及其子部件的边界
|
||||
*/
|
||||
void calculateModelBoundsForPart(ModelPart* part, ThumbnailBounds bounds, Matrix3f parentTransform);
|
||||
|
||||
/**
|
||||
* 计算单个部件的边界
|
||||
*/
|
||||
void calculatePartBounds(ModelPart* part, ThumbnailBounds bounds, Matrix3f worldTransform);
|
||||
|
||||
/**
|
||||
* 构建缩略图专用的正交投影矩阵
|
||||
*/
|
||||
Matrix3f buildThumbnailProjection(GLfloat width, GLfloat height);
|
||||
|
||||
/**
|
||||
* 缩略图专用的部件渲染
|
||||
*/
|
||||
void renderPartForThumbnail(ModelPart* part, Matrix3f parentTransform);
|
||||
|
||||
/**
|
||||
* 缩略图专用的网格渲染
|
||||
*/
|
||||
void renderMeshForThumbnail(Mesh2D* mesh, Matrix3f modelMatrix);
|
||||
|
||||
/**
|
||||
* 设置缩略图专用的简化光照
|
||||
*/
|
||||
void setupThumbnailLighting(ShaderProgram* sp, Model2D& model);
|
||||
|
||||
|
||||
/**
|
||||
* 设置所有非默认着色器的顶点坐标相关uniform
|
||||
*/
|
||||
void setupNonDefaultShaders(Matrix3f projection, Matrix3f view);
|
||||
|
||||
void renderLightPositions(Model2D& model);
|
||||
|
||||
/**
|
||||
* 绘制简洁的灯泡形状
|
||||
*
|
||||
* @param position 灯泡位置
|
||||
* @param intensity 光源强度,用于控制灯泡大小
|
||||
*/
|
||||
void drawLightBulb(Vector2f position, GLfloat intensity);
|
||||
|
||||
/**
|
||||
* 绘制十字标记(用于环境光)
|
||||
*/
|
||||
void drawCrossMark(Vector2f position, GLfloat size);
|
||||
|
||||
/**
|
||||
* 关键修改点:在渲染前确保更新 part 的 worldTransform,
|
||||
* 然后直接使用 part.getWorldTransform() 作为 uModelMatrix 传入 shader。
|
||||
*/
|
||||
void renderPartRecursive(ModelPart* part, Matrix3f parentMat);
|
||||
|
||||
void renderMesh(Mesh2D* mesh, Matrix3f modelMatrix);
|
||||
|
||||
|
||||
// ================== 渲染碰撞箱相关实现 ==================
|
||||
|
||||
void renderPhysicsColliders(PhysicsSystem* physics);
|
||||
|
||||
|
||||
/**
|
||||
* 绘制圆形碰撞框(线框)
|
||||
* 使用临时 VAO/VBO,每帧创建并删除(简单实现)
|
||||
*/
|
||||
void drawCircleColliderWire(Vector2f center, GLfloat radius);
|
||||
|
||||
/**
|
||||
* 绘制矩形碰撞框(线框)
|
||||
*/
|
||||
void drawRectangleColliderWire(Vector2f center, GLfloat width, GLfloat height);
|
||||
|
||||
// ================== uniform 设置辅助(内部使用,确保 program 已绑定) ==================
|
||||
|
||||
void setUniformIntInternal(ShaderProgram* sp, std::string name, int value);
|
||||
|
||||
void setUniformVec3Internal(ShaderProgram* sp, std::string name, Vector3f vec);
|
||||
|
||||
void setUniformVec2Internal(ShaderProgram* sp, std::string name, Vector2f vec);
|
||||
|
||||
void setUniformFloatInternal(ShaderProgram* sp, std::string name, GLfloat value);
|
||||
|
||||
void setUniformVec4Internal(ShaderProgram* sp, std::string name, Vector4f vec);
|
||||
|
||||
void setUniformMatrix3(ShaderProgram* sp, std::string name, Matrix3f m);
|
||||
|
||||
// ================== 部件属性 ==================
|
||||
void setPartUniforms(ShaderProgram* sp, ModelPart* part);
|
||||
|
||||
|
||||
|
||||
};
|
||||
11
Vivid2DRenderer/Object.h
Normal file
11
Vivid2DRenderer/Object.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
|
||||
class Object {
|
||||
public:
|
||||
virtual ~Object() = default;
|
||||
// RTTI
|
||||
|
||||
virtual std::string getClassName() const = 0;
|
||||
|
||||
};
|
||||
318
Vivid2DRenderer/TextRenderer.cpp
Normal file
318
Vivid2DRenderer/TextRenderer.cpp
Normal file
@@ -0,0 +1,318 @@
|
||||
#include "pch.h"
|
||||
|
||||
#include "TextRenderer.h"
|
||||
#include <systems/sources/ShaderProgram.h>
|
||||
#include "systems/RenderSystem.h"
|
||||
#include <systems/sources/ShaderManagement.h>
|
||||
#include <systems/buffer/Tesselator.h>
|
||||
#include "AlignedMemoryStack.h"
|
||||
|
||||
typedef Vivid2D::Render::Buffer::Tesselator Tesselator;
|
||||
typedef Vivid2D::Render::Buffer::BufferBuilder BufferBuilder;
|
||||
|
||||
Logger TextRenderer::logger{ "TextRenderer" };
|
||||
int TextRenderer::CHINESE_FIRST_CHAR = 0x4E00; // CJK Unified Ideographs 常用汉字起始范围
|
||||
int TextRenderer::CHINESE_CHAR_COUNT = 20000;
|
||||
|
||||
TextRenderer::TextRenderer(int bitmapWidth, int bitmapHeight, int firstChar, int charCount)
|
||||
: bitmapWidth(bitmapWidth),
|
||||
bitmapHeight(bitmapHeight),
|
||||
firstChar(firstChar),
|
||||
charCount(charCount)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 初始化字体渲染器
|
||||
*/
|
||||
void TextRenderer::initialize(ByteBuffer fontData, float fontHeight)
|
||||
{
|
||||
if (initialized) {
|
||||
logger.warning("TextRenderer already initialized");
|
||||
return;
|
||||
}
|
||||
if (fontData.empty() || fontHeight <= 0) {
|
||||
logger.error("Invalid font data or font height");
|
||||
return;
|
||||
}
|
||||
|
||||
ShaderProgram* shader = ShaderManagement::getShaderProgram("TextShader");
|
||||
if (!shader) {
|
||||
logger.error("TextShader not found");
|
||||
return;
|
||||
}
|
||||
|
||||
shader->use();
|
||||
|
||||
try {
|
||||
asciiCharData.resize(charCount);
|
||||
ByteBuffer asciiBitmap(bitmapWidth * bitmapHeight);
|
||||
int asciiRes = stbtt_BakeFontBitmap(
|
||||
fontData.data(),
|
||||
0, fontHeight,
|
||||
asciiBitmap.data(),
|
||||
bitmapWidth, bitmapHeight, firstChar, charCount,
|
||||
asciiCharData.data());
|
||||
if (asciiRes <= 0) {
|
||||
logger.error("ASCII font bake failed, result: {}", asciiRes);
|
||||
cleanup();
|
||||
return;
|
||||
}
|
||||
asciiTextureId = createTextureFromBitmap(bitmapWidth, bitmapHeight, asciiBitmap);
|
||||
if (asciiTextureId == 0) {
|
||||
logger.error("Failed to create ASCII texture");
|
||||
cleanup();
|
||||
return;
|
||||
}
|
||||
|
||||
// 烘焙中文 - 使用更大的纹理和正确的字符范围
|
||||
int chineseTexSize = 4096; // 中文字符需要更大的纹理
|
||||
// 分配足够的空间来存储 CHINESE_CHAR_COUNT 个字符的数据
|
||||
chineseCharData.resize(CHINESE_CHAR_COUNT);
|
||||
ByteBuffer chineseBitmap(chineseTexSize * chineseTexSize);
|
||||
// 关键:烘焙从 CHINESE_FIRST_CHAR 开始的 CHINESE_CHAR_COUNT 个连续字符
|
||||
int chineseRes = stbtt_BakeFontBitmap(fontData.data(),
|
||||
0, fontHeight,
|
||||
chineseBitmap.data(),
|
||||
chineseTexSize, chineseTexSize, CHINESE_FIRST_CHAR, CHINESE_CHAR_COUNT,
|
||||
chineseCharData.data());
|
||||
if (chineseRes <= 0) {
|
||||
logger.error("Chinese font bake failed, result: {}", chineseRes);
|
||||
cleanup();
|
||||
return;
|
||||
}
|
||||
chineseTextureId = createTextureFromBitmap(chineseTexSize, chineseTexSize, chineseBitmap);
|
||||
if (chineseTextureId == 0) {
|
||||
logger.error("Failed to create Chinese texture");
|
||||
cleanup();
|
||||
return;
|
||||
}
|
||||
|
||||
initialized = true;
|
||||
logger.debug("TextRenderer initialized, ASCII tex={}, Chinese tex={}", asciiTextureId, chineseTextureId);
|
||||
|
||||
}
|
||||
catch (std::exception e) {
|
||||
logger.error("Exception during TextRenderer init: {}", e.what(), e);
|
||||
cleanup();
|
||||
}
|
||||
catch (...) {
|
||||
logger.error("Unknown exception during TextRenderer init");
|
||||
cleanup();
|
||||
}
|
||||
shader->stop();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 获取一行文字的宽度(带缩放)
|
||||
*/
|
||||
float TextRenderer::getTextWidth(std::string text, float scale) const
|
||||
{
|
||||
if (!initialized || text.empty()) return 0.0f;
|
||||
|
||||
float width = 0.0f;
|
||||
|
||||
for (int i = 0; i < text.length(); i++) {
|
||||
char c = text[i];
|
||||
if (c >= firstChar && c < firstChar + charCount) {
|
||||
BakedChar bakedChar = asciiCharData[c - firstChar];
|
||||
width += bakedChar.xadvance * scale;
|
||||
}
|
||||
else {
|
||||
// 修复中文索引逻辑:检查字符是否在烘焙的连续范围内
|
||||
if (c >= CHINESE_FIRST_CHAR && c < CHINESE_FIRST_CHAR + CHINESE_CHAR_COUNT) {
|
||||
int idx = c - CHINESE_FIRST_CHAR; // 关键:使用 Unicode 差值作为索引
|
||||
BakedChar bakedChar = chineseCharData[idx];
|
||||
width += bakedChar.xadvance * scale;
|
||||
}
|
||||
else {
|
||||
// 对于未找到的字符,使用空格宽度
|
||||
width += 0.5f * scale; // 估计值
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return width;
|
||||
}
|
||||
|
||||
void TextRenderer::renderText(std::string text, float x, float y, Vector4f color, float scale)
|
||||
{
|
||||
if (!initialized || text.empty()) return;
|
||||
if (scale <= 0.0f) scale = 1.0f;
|
||||
|
||||
RenderSystem::assertOnRenderThread();
|
||||
RenderSystem::pushState();
|
||||
try {
|
||||
ShaderProgram* shader = ShaderManagement::getShaderProgram("TextShader");
|
||||
if (!shader) {
|
||||
logger.error("TextShader not found");
|
||||
return;
|
||||
}
|
||||
shader->use();
|
||||
ShaderManagement::setUniformVec4(shader, "uColor", color);
|
||||
ShaderManagement::setUniformInt(shader, "uTexture", 0);
|
||||
|
||||
RenderSystem::enableBlend();
|
||||
RenderSystem::blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
RenderSystem::disableDepthTest();
|
||||
|
||||
thread_local AlignedMemoryStack stack;
|
||||
try {
|
||||
auto* q = stack.pushStackAllocate<AlignedQuad>(sizeof(AlignedQuad));
|
||||
float xpos = x;
|
||||
float ypos = y;
|
||||
|
||||
Tesselator& t = Tesselator::getInstance();
|
||||
BufferBuilder& builder = t.getBuilder();
|
||||
|
||||
// 按字符类型分组渲染以减少纹理切换
|
||||
int currentTexture = -1;
|
||||
bool batchStarted = false;
|
||||
|
||||
for (int i = 0; i < text.length(); i++) {
|
||||
char c = text[i];
|
||||
int targetTexture;
|
||||
BakedCharBuffer charBuffer;
|
||||
int texWidth, texHeight;
|
||||
|
||||
if (c >= firstChar && c < firstChar + charCount) {
|
||||
targetTexture = asciiTextureId;
|
||||
charBuffer = asciiCharData;
|
||||
texWidth = bitmapWidth;
|
||||
texHeight = bitmapHeight;
|
||||
stbtt_GetBakedQuad(charBuffer.data(), texWidth, texHeight, c - firstChar, &xpos, &ypos, q, true);
|
||||
}
|
||||
else {
|
||||
// 修复中文索引逻辑:检查字符是否在烘焙的连续范围内
|
||||
if (c >= CHINESE_FIRST_CHAR && c < CHINESE_FIRST_CHAR + CHINESE_CHAR_COUNT) {
|
||||
targetTexture = chineseTextureId;
|
||||
charBuffer = chineseCharData;
|
||||
texWidth = 4096;
|
||||
texHeight = 4096;
|
||||
// 关键修复:索引是字符的 Unicode 减去起始 Unicode
|
||||
int idx = c - CHINESE_FIRST_CHAR;
|
||||
stbtt_GetBakedQuad(charBuffer.data(), texWidth, texHeight, idx, &xpos, &ypos, q, true);
|
||||
}
|
||||
else {
|
||||
continue; // 跳过不支持的字符
|
||||
}
|
||||
}
|
||||
|
||||
// 如果纹理改变,结束当前批次
|
||||
if (targetTexture != currentTexture) {
|
||||
if (batchStarted) {
|
||||
t.end();
|
||||
batchStarted = false;
|
||||
}
|
||||
RenderSystem::bindTexture(targetTexture);
|
||||
currentTexture = targetTexture;
|
||||
}
|
||||
|
||||
// 开始新批次(如果需要)
|
||||
if (!batchStarted) {
|
||||
builder.begin(GL_TRIANGLES, (text.length() - i) * 6);
|
||||
batchStarted = true;
|
||||
}
|
||||
|
||||
// 应用缩放并计算顶点
|
||||
float sx0 = x + (q->x0 - x) * scale;
|
||||
float sx1 = x + (q->x1 - x) * scale;
|
||||
float sy0 = y + (q->y0 - y) * scale;
|
||||
float sy1 = y + (q->y1 - y) * scale;
|
||||
|
||||
builder.vertex(sx0, sy0, q->s0, q->t0);
|
||||
builder.vertex(sx1, sy0, q->s1, q->t0);
|
||||
builder.vertex(sx0, sy1, q->s0, q->t1);
|
||||
|
||||
builder.vertex(sx1, sy0, q->s1, q->t0);
|
||||
builder.vertex(sx1, sy1, q->s1, q->t1);
|
||||
builder.vertex(sx0, sy1, q->s0, q->t1);
|
||||
}
|
||||
|
||||
// 结束最后一个批次
|
||||
if (batchStarted) {
|
||||
t.end();
|
||||
}
|
||||
stack.popStack();
|
||||
}
|
||||
catch (...) {
|
||||
stack.popStack();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
catch (std::exception e) {
|
||||
logger.error("Error rendering text: {}", e.what(), e);
|
||||
}
|
||||
catch (...) {
|
||||
logger.error("Unknown error rendering text");
|
||||
}
|
||||
RenderSystem::popState();
|
||||
}
|
||||
|
||||
int TextRenderer::createTextureFromBitmap(int width, int height, ByteBuffer pixels)
|
||||
{
|
||||
RenderSystem::assertOnRenderThread();
|
||||
try {
|
||||
int textureId = RenderSystem::genTextures();
|
||||
RenderSystem::bindTexture(textureId);
|
||||
|
||||
RenderSystem::pixelStore(GL_UNPACK_ALIGNMENT, 1);
|
||||
RenderSystem::texImage2D(GL_TEXTURE_2D, 0, GL_R8, width, height, 0,
|
||||
GL_RED, GL_UNSIGNED_BYTE, pixels.data());
|
||||
|
||||
RenderSystem::setTextureMinFilter(GL_LINEAR);
|
||||
RenderSystem::setTextureMagFilter(GL_LINEAR);
|
||||
RenderSystem::setTextureWrapS(GL_CLAMP_TO_EDGE);
|
||||
RenderSystem::setTextureWrapT(GL_CLAMP_TO_EDGE);
|
||||
|
||||
// 设置纹理swizzle以便单通道纹理在着色器中显示为白色
|
||||
RenderSystem::texParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_RED);
|
||||
RenderSystem::texParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_RED);
|
||||
RenderSystem::texParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED);
|
||||
RenderSystem::texParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_RED);
|
||||
|
||||
RenderSystem::pixelStore(GL_UNPACK_ALIGNMENT, 4);
|
||||
RenderSystem::bindTexture(0);
|
||||
|
||||
return textureId;
|
||||
}
|
||||
catch (std::exception e) {
|
||||
logger.error("Failed to create texture from bitmap: {}", e.what(), e);
|
||||
return 0;
|
||||
}
|
||||
catch (...) {
|
||||
logger.error("Unknown error creating texture from bitmap");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void TextRenderer::cleanup()
|
||||
{
|
||||
RenderSystem::assertOnRenderThread();
|
||||
if (asciiTextureId != 0)
|
||||
{
|
||||
RenderSystem::deleteTextures(asciiTextureId);
|
||||
asciiTextureId = 0;
|
||||
}
|
||||
if (chineseTextureId != 0)
|
||||
{
|
||||
RenderSystem::deleteTextures(chineseTextureId);
|
||||
chineseTextureId = 0;
|
||||
}
|
||||
if (!asciiCharData.empty())
|
||||
{
|
||||
asciiCharData.clear();
|
||||
asciiCharData.shrink_to_fit();
|
||||
}
|
||||
if (!chineseCharData.empty())
|
||||
{
|
||||
chineseCharData.clear();
|
||||
chineseCharData.shrink_to_fit();
|
||||
}
|
||||
initialized = false;
|
||||
logger.debug("TextRenderer cleaned up");
|
||||
}
|
||||
|
||||
80
Vivid2DRenderer/TextRenderer.h
Normal file
80
Vivid2DRenderer/TextRenderer.h
Normal file
@@ -0,0 +1,80 @@
|
||||
#pragma once
|
||||
#include <Logger.h>
|
||||
|
||||
#include <string_view>
|
||||
|
||||
#include <glm/vec4.hpp>
|
||||
#include <stb_truetype.h>
|
||||
|
||||
namespace glm {
|
||||
struct vec4;
|
||||
}
|
||||
|
||||
class TextRenderer
|
||||
{
|
||||
private:
|
||||
|
||||
using Vector4f = glm::vec4;
|
||||
using BakedChar = stbtt_bakedchar;
|
||||
using BakedCharBuffer = std::vector<BakedChar>;
|
||||
using ByteBuffer = std::vector<unsigned char>;
|
||||
using AlignedQuad = stbtt_aligned_quad;
|
||||
static Logger logger;
|
||||
|
||||
int bitmapWidth = 512;
|
||||
int bitmapHeight = 512;
|
||||
int firstChar = 32;
|
||||
int charCount = 96;
|
||||
|
||||
BakedCharBuffer asciiCharData;
|
||||
BakedCharBuffer chineseCharData;
|
||||
int asciiTextureId = 0;
|
||||
int chineseTextureId = 0;
|
||||
|
||||
bool initialized = false;
|
||||
|
||||
// 中文字符起始编码(选择一个不冲突的范围)
|
||||
static int CHINESE_FIRST_CHAR; // CJK Unified Ideographs 常用汉字起始范围
|
||||
static int CHINESE_CHAR_COUNT;
|
||||
|
||||
public:
|
||||
TextRenderer(int bitmapWidth, int bitmapHeight, int firstChar, int charCount);
|
||||
void initialize(ByteBuffer, float);
|
||||
bool isInitialized() const;
|
||||
|
||||
|
||||
float getTextWidth(std::string text, float scale) const;
|
||||
/**
|
||||
* 获取一行文字的宽度(单位:像素)
|
||||
*/
|
||||
float getTextWidth(std::string text) const {
|
||||
return getTextWidth(text, 1.0f);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 渲染文字
|
||||
*/
|
||||
void renderText(std::string text, float x, float y, Vector4f color, float scale);
|
||||
void renderText(std::string text, float x, float y, Vector4f color) {
|
||||
renderText(text, x, y, color, 1.0f);
|
||||
}
|
||||
|
||||
int createTextureFromBitmap(int width, int height, ByteBuffer pixels);
|
||||
|
||||
void cleanup();
|
||||
|
||||
bool isInitialized() const {
|
||||
return initialized;
|
||||
}
|
||||
|
||||
int getAsciiTextureId() const {
|
||||
return asciiTextureId;
|
||||
}
|
||||
|
||||
int getChineseTextureId() const {
|
||||
return chineseTextureId;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
@@ -70,6 +70,13 @@
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<IncludePath>libs\logger\include;$(ProjectDir);$(IncludePath)</IncludePath>
|
||||
<LibraryPath>libs\logger\build\Debugx64;$(LibraryPath)</LibraryPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Vcpkg">
|
||||
<VcpkgEnableManifest>true</VcpkgEnableManifest>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
@@ -112,11 +119,13 @@
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
<AdditionalDependencies>Logger_d.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
@@ -209,6 +218,8 @@ endlocal
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="AlignedMemoryStack.h" />
|
||||
<ClInclude Include="ModelRender.h" />
|
||||
<ClInclude Include="model\AnimationParameter.h" />
|
||||
<ClInclude Include="model\FrameInterpolator.h" />
|
||||
<ClInclude Include="model\util\AnimationClip.h" />
|
||||
@@ -221,10 +232,12 @@ endlocal
|
||||
<ClInclude Include="model\util\ModelPose.h" />
|
||||
<ClInclude Include="model\util\PhysicsSystem.h" />
|
||||
<ClInclude Include="model\util\VertexList.h" />
|
||||
<ClInclude Include="Object.h" />
|
||||
<ClInclude Include="systems\buffer\BufferUploader.h" />
|
||||
<ClInclude Include="systems\buffer\BufferBuilder.h" />
|
||||
<ClInclude Include="framework.h" />
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="systems\Camera.h" />
|
||||
<ClInclude Include="systems\MultiSelectionBoxRenderer.h" />
|
||||
<ClInclude Include="systems\sources\def\Shader2D.h" />
|
||||
<ClInclude Include="systems\sources\def\SolidColorShader.h" />
|
||||
@@ -237,8 +250,11 @@ endlocal
|
||||
<ClInclude Include="systems\buffer\Tesselator.h" />
|
||||
<ClInclude Include="model\util\Vertex.h" />
|
||||
<ClInclude Include="systems\Texture.h" />
|
||||
<ClInclude Include="TextRenderer.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="AlignedMemoryStack.cpp" />
|
||||
<ClCompile Include="ModelRender.cpp" />
|
||||
<ClCompile Include="model\AnimationParameter.cpp" />
|
||||
<ClCompile Include="model\FrameInterpolator.cpp" />
|
||||
<ClCompile Include="model\util\AnimationClip.cpp" />
|
||||
@@ -260,6 +276,7 @@ endlocal
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="systems\Camera.cpp" />
|
||||
<ClCompile Include="systems\MultiSelectionBoxRenderer.cpp" />
|
||||
<ClCompile Include="systems\sources\def\Shader2D.cpp" />
|
||||
<ClCompile Include="systems\sources\def\SolidColorShader.cpp" />
|
||||
@@ -270,6 +287,7 @@ endlocal
|
||||
<ClCompile Include="systems\buffer\Tesselator.cpp" />
|
||||
<ClCompile Include="model\util\Vertex.cpp" />
|
||||
<ClCompile Include="systems\Texture.cpp" />
|
||||
<ClCompile Include="TextRenderer.cpp" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets" />
|
||||
|
||||
@@ -13,6 +13,27 @@
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="源文件\systems">
|
||||
<UniqueIdentifier>{aace2215-85f9-46d7-aa76-35c982fe4c00}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="源文件\systems\buffer">
|
||||
<UniqueIdentifier>{780d2429-421a-438d-9602-8e7b1d7e9975}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="源文件\systems\sources">
|
||||
<UniqueIdentifier>{1fb8ab3b-c4ca-4647-ad21-9ae610ea6d30}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="源文件\systems\sources\def">
|
||||
<UniqueIdentifier>{f052c1ce-f35a-4901-8922-116e4991b2a6}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="源文件\model">
|
||||
<UniqueIdentifier>{8fa89cd9-6cd6-411a-80d2-4a27e482f1c0}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="源文件\model\util">
|
||||
<UniqueIdentifier>{fba61944-faac-4a9d-a29c-fccc95a13587}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="头文件\systems">
|
||||
<UniqueIdentifier>{555ebff3-f682-47fe-9316-2cc820ab476b}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="framework.h">
|
||||
@@ -21,9 +42,6 @@
|
||||
<ClInclude Include="pch.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="systems\RenderSystem.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="systems\sources\ShaderProgram.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
@@ -60,18 +78,12 @@
|
||||
<ClInclude Include="model\util\VertexList.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="systems\Texture.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="model\util\BoundingBox.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="model\Mesh2D.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="systems\MultiSelectionBoxRenderer.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="model\ModelPart.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
@@ -99,6 +111,30 @@
|
||||
<ClInclude Include="model\FrameInterpolator.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ModelRender.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="systems\Camera.h">
|
||||
<Filter>头文件\systems</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="systems\Texture.h">
|
||||
<Filter>头文件\systems</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="systems\MultiSelectionBoxRenderer.h">
|
||||
<Filter>头文件\systems</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="systems\RenderSystem.h">
|
||||
<Filter>头文件\systems</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="TextRenderer.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Object.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="AlignedMemoryStack.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="dllmain.cpp">
|
||||
@@ -107,76 +143,88 @@
|
||||
<ClCompile Include="pch.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ModelRender.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="systems\RenderSystem.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="systems\sources\ShaderProgram.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="systems\sources\ShaderManagement.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="systems\sources\def\TextShader.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="systems\sources\def\SolidColorShader.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="systems\sources\def\Shader2D.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="systems\buffer\Tesselator.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="systems\buffer\BufferBuilder.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="systems\buffer\BufferUploader.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="model\util\Vertex.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="model\util\VertexList.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="systems\Texture.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="model\util\BoundingBox.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="model\Mesh2D.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
<Filter>源文件\systems</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="systems\MultiSelectionBoxRenderer.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
<Filter>源文件\systems</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="model\ModelPart.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
<ClCompile Include="systems\Texture.cpp">
|
||||
<Filter>源文件\systems</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="systems\Camera.cpp">
|
||||
<Filter>源文件\systems</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="systems\buffer\BufferBuilder.cpp">
|
||||
<Filter>源文件\systems\buffer</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="systems\buffer\BufferUploader.cpp">
|
||||
<Filter>源文件\systems\buffer</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="systems\buffer\Tesselator.cpp">
|
||||
<Filter>源文件\systems\buffer</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="systems\sources\ShaderProgram.cpp">
|
||||
<Filter>源文件\systems\sources</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="systems\sources\ShaderManagement.cpp">
|
||||
<Filter>源文件\systems\sources</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="systems\sources\def\Shader2D.cpp">
|
||||
<Filter>源文件\systems\sources\def</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="systems\sources\def\SolidColorShader.cpp">
|
||||
<Filter>源文件\systems\sources\def</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="systems\sources\def\TextShader.cpp">
|
||||
<Filter>源文件\systems\sources\def</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="model\AnimationParameter.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="model\util\LightSource.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="model\util\ModelPose.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
<Filter>源文件\model</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="model\Model2D.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
<Filter>源文件\model</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="model\util\PhysicsSystem.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
<ClCompile Include="model\Mesh2D.cpp">
|
||||
<Filter>源文件\model</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="model\util\AnimationLayer.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="model\util\AnimationClip.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
<ClCompile Include="model\ModelPart.cpp">
|
||||
<Filter>源文件\model</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="model\FrameInterpolator.cpp">
|
||||
<Filter>源文件\model</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="model\util\AnimationClip.cpp">
|
||||
<Filter>源文件\model\util</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="model\util\AnimationLayer.cpp">
|
||||
<Filter>源文件\model\util</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="model\util\BoundingBox.cpp">
|
||||
<Filter>源文件\model\util</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="model\util\LightSource.cpp">
|
||||
<Filter>源文件\model\util</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="model\util\ModelPose.cpp">
|
||||
<Filter>源文件\model\util</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="model\util\PhysicsSystem.cpp">
|
||||
<Filter>源文件\model\util</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="model\util\Vertex.cpp">
|
||||
<Filter>源文件\model\util</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="model\util\VertexList.cpp">
|
||||
<Filter>源文件\model\util</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="TextRenderer.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="AlignedMemoryStack.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -168,7 +168,7 @@ public:
|
||||
virtual ~LoggerInterface() = default;
|
||||
virtual void setLevel(LogLevel level) noexcept(false) = 0;
|
||||
virtual void setGlobalLevel(LogLevel level) noexcept(false) = 0;
|
||||
virtual void level() const noexcept = 0;
|
||||
virtual LogLevel level() const noexcept = 0;
|
||||
virtual LoggerStream trace() noexcept = 0;
|
||||
virtual LoggerStream debug() noexcept = 0;
|
||||
virtual LoggerStream info() noexcept = 0;
|
||||
@@ -275,6 +275,7 @@ public:
|
||||
~Logger();
|
||||
void setGlobalLevel(LogLevel level) noexcept(false) override;
|
||||
void setLevel(LogLevel level) noexcept(false) override;
|
||||
LogLevel level() const noexcept override;
|
||||
// 流式日志打印
|
||||
LoggerStream trace() noexcept override;
|
||||
LoggerStream debug() noexcept override;
|
||||
@@ -288,6 +289,41 @@ public:
|
||||
void warning(const std::string &msg) noexcept override;
|
||||
void error(const std::string &msg) noexcept override;
|
||||
void critical(const std::string &msg) noexcept override;
|
||||
|
||||
// fmt + args
|
||||
template <typename... Args>
|
||||
void trace(const std::string& fmt, Args &&...args) noexcept {
|
||||
_loggerHelper(&LoggerInterface::trace, fmt, std::forward<Args>(args)...);
|
||||
}
|
||||
template <typename... Args>
|
||||
void debug(const std::string& fmt, Args &&...args) noexcept {
|
||||
_loggerHelper(&LoggerInterface::debug, fmt, std::forward<Args>(args)...);
|
||||
}
|
||||
template <typename... Args>
|
||||
void info(const std::string& fmt, Args &&...args) noexcept {
|
||||
_loggerHelper(&LoggerInterface::info, fmt, std::forward<Args>(args)...);
|
||||
}
|
||||
template <typename... Args>
|
||||
void warning(const std::string& fmt, Args &&...args) noexcept {
|
||||
_loggerHelper(&LoggerInterface::warning, fmt, std::forward<Args>(args)...);
|
||||
}
|
||||
template <typename... Args>
|
||||
void error(const std::string& fmt, Args &&...args) noexcept {
|
||||
_loggerHelper(&LoggerInterface::error, fmt, std::forward<Args>(args)...);
|
||||
}
|
||||
template <typename... Args>
|
||||
void critical(const std::string& fmt, Args &&...args) noexcept {
|
||||
_loggerHelper(&LoggerInterface::critical, fmt, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename... Args>
|
||||
void _loggerHelper(void (LoggerInterface::* func)(const std::string&), const std::string& fmt, Args &&...args) noexcept {
|
||||
std::string formattedMsg = LoggerFormatNS::format(fmt, std::forward<Args>(args)...);
|
||||
// 处理后交给具体的日志实现
|
||||
(this->*func)(formattedMsg);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -52,7 +52,36 @@ public:
|
||||
}
|
||||
return spdLevel;
|
||||
}
|
||||
|
||||
static LogLevel spdLogLevelToLogLevel(SpdLogLevel level) {
|
||||
LogLevel l = LogLevel::trace;
|
||||
switch (level)
|
||||
{
|
||||
case SpdLogUtils::SpdLogLevel::trace:
|
||||
l = LogLevel::trace;
|
||||
break;
|
||||
case SpdLogUtils::SpdLogLevel::debug:
|
||||
l = LogLevel::debug;
|
||||
break;
|
||||
case SpdLogUtils::SpdLogLevel::info:
|
||||
l = LogLevel::info;
|
||||
break;
|
||||
case SpdLogUtils::SpdLogLevel::warning:
|
||||
l = LogLevel::warning;
|
||||
break;
|
||||
case SpdLogUtils::SpdLogLevel::error:
|
||||
l = LogLevel::error;
|
||||
break;
|
||||
case SpdLogUtils::SpdLogLevel::critical:
|
||||
l = LogLevel::critical;
|
||||
break;
|
||||
case SpdLogUtils::SpdLogLevel::off:
|
||||
l = LogLevel::off;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return l;
|
||||
}
|
||||
typedef spdlog::color_mode SpdLogColorMode;
|
||||
static SpdLogColorMode logColorModeToSpdLogColorMode(LogColorMode colorMode) {
|
||||
SpdLogColorMode cm = SpdLogColorMode::automatic;
|
||||
@@ -268,6 +297,11 @@ void Logger::setLevel(LogLevel level) noexcept(false)
|
||||
}
|
||||
}
|
||||
|
||||
LogLevel Logger::level() const noexcept
|
||||
{
|
||||
//level::level_enum logger::level()
|
||||
return SpdLogUtils::spdLogLevelToLogLevel(static_cast<SpdLogUtils::SpdLogLevel>(pImpl->logger->level()));
|
||||
}
|
||||
|
||||
// 带参数日志打印
|
||||
void Logger::trace(const std::string &msg) noexcept
|
||||
|
||||
@@ -382,7 +382,7 @@ namespace Vivid2D {
|
||||
* @brief 获取模型的物理系统。
|
||||
* @return 指向物理系统的常量指针。
|
||||
*/
|
||||
const util::PhysicsSystem* getPhysics() const { return m_physics.get(); }
|
||||
util::PhysicsSystem* getPhysics() { return m_physics.get(); }
|
||||
|
||||
/**
|
||||
* @brief 获取模型当前应用的姿态。
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
#include <unordered_map>
|
||||
#include <memory>
|
||||
#include <chrono>
|
||||
#include <Object.h>
|
||||
|
||||
|
||||
namespace Vivid2D {
|
||||
class Model2D;
|
||||
@@ -299,7 +301,7 @@ namespace Vivid2D::util {
|
||||
/**
|
||||
* 物理碰撞体接口
|
||||
*/
|
||||
struct VIVID_2D_MYDLL_API PhysicsCollider {
|
||||
struct VIVID_2D_MYDLL_API PhysicsCollider : public Object {
|
||||
virtual ~PhysicsCollider() = default;
|
||||
virtual bool collidesWith(const PhysicsParticle& particle) const = 0;
|
||||
virtual void resolveCollision(PhysicsParticle& particle, float deltaTime) = 0;
|
||||
@@ -313,6 +315,7 @@ namespace Vivid2D::util {
|
||||
*/
|
||||
class VIVID_2D_MYDLL_API CircleCollider : public PhysicsCollider {
|
||||
public:
|
||||
std::string getClassName() const override { return "CircleCollider"; }
|
||||
CircleCollider(std::string id, glm::vec2 center, float radius);
|
||||
bool collidesWith(const PhysicsParticle& particle) const override;
|
||||
void resolveCollision(PhysicsParticle& particle, float deltaTime) override;
|
||||
@@ -337,6 +340,7 @@ namespace Vivid2D::util {
|
||||
*/
|
||||
class VIVID_2D_MYDLL_API RectangleCollider : public PhysicsCollider {
|
||||
public:
|
||||
std::string getClassName() const override { return "RectangleCollider"; }
|
||||
RectangleCollider(std::string id, glm::vec2 center, float width, float height);
|
||||
bool collidesWith(const PhysicsParticle& particle) const override;
|
||||
void resolveCollision(PhysicsParticle& particle, float deltaTime) override;
|
||||
|
||||
94
Vivid2DRenderer/systems/Camera.cpp
Normal file
94
Vivid2DRenderer/systems/Camera.cpp
Normal file
@@ -0,0 +1,94 @@
|
||||
#include "Camera.h"
|
||||
#include <glm/vec2.hpp>
|
||||
#include <algorithm>
|
||||
|
||||
Camera::Camera()
|
||||
: m_pos(new Vector2f(0.0f, 0.0f))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Camera::Camera(float x, float y)
|
||||
: m_pos(new Vector2f(x, y))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Camera::Camera(const Camera& other)
|
||||
: m_pos(new Vector2f(other.m_pos->x, other.m_pos->y))
|
||||
, m_zoom(other.m_zoom)
|
||||
, m_zPos(other.m_zPos)
|
||||
, m_enabled(other.m_enabled)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Camera::~Camera()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Camera::setPosition(float x, float y)
|
||||
{
|
||||
*m_pos = Vector2f(x, y);
|
||||
}
|
||||
|
||||
void Camera::setPosition(Vector2f pos)
|
||||
{
|
||||
*m_pos = pos;
|
||||
}
|
||||
|
||||
Camera::Vector2f Camera::getPosition() const
|
||||
{
|
||||
return *m_pos;
|
||||
}
|
||||
|
||||
void Camera::setZoom(float zoom)
|
||||
{
|
||||
this->m_zoom = std::max(0.1f, std::min(10.0f, zoom));
|
||||
}
|
||||
|
||||
float Camera::getZoom() const
|
||||
{
|
||||
return m_zoom;
|
||||
}
|
||||
|
||||
void Camera::setZPosition(float z)
|
||||
{
|
||||
this->m_zPos = z;
|
||||
}
|
||||
|
||||
float Camera::getZPosition() const
|
||||
{
|
||||
return m_zPos;
|
||||
}
|
||||
|
||||
void Camera::setEnabled(bool enabled)
|
||||
{
|
||||
this->m_enabled = enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取摄像机是否启用
|
||||
*/
|
||||
bool Camera::isEnabled() const
|
||||
{
|
||||
return m_enabled;
|
||||
}
|
||||
|
||||
void Camera::move(float dx, float dy)
|
||||
{
|
||||
*m_pos += Vector2f(dx, dy);
|
||||
}
|
||||
|
||||
void Camera::zoom(float factor)
|
||||
{
|
||||
m_zoom *= factor;
|
||||
m_zoom = std::max(0.1f, std::min(10.0f, m_zoom));
|
||||
}
|
||||
|
||||
void Camera::reset() {
|
||||
*m_pos = Vector2f(0.0f, 0.0f);
|
||||
m_zoom = 1.0f;
|
||||
m_zPos = 0.0f;
|
||||
}
|
||||
37
Vivid2DRenderer/systems/Camera.h
Normal file
37
Vivid2DRenderer/systems/Camera.h
Normal file
@@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
#include <memory>
|
||||
|
||||
namespace glm {
|
||||
struct vec2;
|
||||
}
|
||||
|
||||
class Camera {
|
||||
public:
|
||||
using Vector2f = glm::vec2;
|
||||
|
||||
private:
|
||||
std::unique_ptr<Vector2f> m_pos;
|
||||
float m_zoom = 1.0f;
|
||||
float m_zPos = 0.0f;
|
||||
bool m_enabled = true;
|
||||
|
||||
public:
|
||||
explicit Camera();
|
||||
explicit Camera(float x, float y);
|
||||
Camera(const Camera& other);
|
||||
~Camera();
|
||||
void setPosition(float x, float y);
|
||||
void setPosition(Vector2f);
|
||||
Vector2f getPosition() const;
|
||||
void setZoom(float);
|
||||
void zoom(float);
|
||||
float getZoom() const;
|
||||
void setZPosition(float);
|
||||
float getZPosition() const;
|
||||
|
||||
void move(float x, float y);
|
||||
void reset();
|
||||
bool isEnabled() const;
|
||||
void setEnabled(bool);
|
||||
|
||||
};
|
||||
Reference in New Issue
Block a user