feat(Logger): Add a universal logger

- Add a Logger framework
- Add a spdlog logger adapter
- Update README and vcpkg.json
- fix some language error
This commit is contained in:
lyxyz5223
2025-11-16 15:10:59 +08:00
parent f4e10bcccc
commit e3b42e4f70
13 changed files with 1078 additions and 136 deletions

4
.gitignore vendored
View File

@@ -360,4 +360,6 @@ MigrationBackup/
.ionide/
# Fody - auto-generated XML schema
FodyWeavers.xsd
FodyWeavers.xsd
**/vcpkg_installed/

View File

@@ -19,21 +19,30 @@
## 二、配置 vcpkg
`vcpkg` 用于下载和安装项目所需的第三方库。
下列方法二选一:
1. **下载并引导 vcpkg:**
1. 手动安装vcpkg
- 1. **下载并引导 vcpkg:**
- 克隆 vcpkg 仓库或下载压缩包。
- 运行引导脚本Windows 上通常是 `.\bootstrap-vcpkg.bat`)。
2. **安装项目依赖库:**
- 2. **安装项目依赖库:**
打开命令行或 PowerShell进入 vcpkg 目录,然后运行以下命令来安装项目所需的库:
```bash
.\vcpkg install glfw3 glew stb glad spdlog glm
.\vcpkg install glfw3 glew stb glad spdlog glm stduuid
```
- 此命令将下载并安装 **glfw3** (窗口和上下文管理)、**glew/glad** (OpenGL 扩展加载)、**stb** (图像处理/加载等)、**spdlog** (日志记录) 和 **glm** (数学库)。
2. 使用Visual Studio Installer安装的vcpkg
- 使用Visual Studio打开项目点击 工具-命令行-开发者命令提示/开发者 PowerShell执行下列命令
- vcpkg integrate install
- (可选)执行下列命令,编译会自动执行
- vcpkg install
## 三、使用 Visual Studio 构建项目
一旦依赖库安装完毕,你可以直接在 Visual Studio 中打开并构建项目。

View File

@@ -0,0 +1,7 @@
rem Build debug version
cl /c /Od /MDd /Zi /D_DEBUG /DUSE_SPDLOG /EHsc /std:c++17 /I include /I..\..\vcpkg_installed\x64-windows\include src\Logger.cpp /Fo:build\Debugx64\Logger_d.obj /utf-8 /Fd:build\Debugx64\Logger_d.pdb
lib /NOLOGO /OUT:build\Debugx64\Logger_d.lib build\Debugx64\Logger_d.obj
rem Build release version
cl /c /O2 /MD /DNDEBUG /DUSE_SPDLOG /EHsc /std:c++17 /I include /I..\..\vcpkg_installed\x64-windows\include src\Logger.cpp /Fo:build\Releasex64\Logger.obj /utf-8 /Fd:build\Releasex64\Logger.pdb
lib /NOLOGO /OUT:build\Releasex64\Logger.lib build\Releasex64\Logger.obj

View File

@@ -0,0 +1,295 @@
#pragma once
#ifndef LOGGER_H
#define LOGGER_H
// C++ 标准库版本判断
#if __cplusplus >= 202002L && defined(USE_STD_FORMAT)
// C++20 或更高版本
#include <format>
namespace LoggerFormatNS = std;
#else
#include <fmt/core.h> // 仅基础格式化
#include <fmt/format.h> // 完整功能
namespace LoggerFormatNS = fmt;
#endif
#include <string>
#include <memory>
#include <functional>
#include <iostream>
#include <any>
// 用于支持 << 流式传递打印日志
// LoggerStream.h
#include <sstream>
#include <string>
#include <functional>
// 日志打印等级
enum class LogLevel : int
{
trace,
debug,
info,
warning,
error,
critical,
off
};
// 日志打印的颜色模式(如黑白或彩色)
enum class LogColorMode : int
{
automatic,
always,
never
};
class LoggerInterface; // 前置声明
class Logger;
// 辅助类:流式日志打印
class LoggerStream
{
public:
LoggerStream(LoggerInterface *logger, std::function<void(const std::string &)> log_func)
: logger(logger), logFunc(log_func) {}
// 允许移动
LoggerStream(LoggerStream &&) noexcept = default;
LoggerStream &operator=(LoggerStream &&) noexcept = default;
// 禁止拷贝
LoggerStream(const LoggerStream &) = delete;
LoggerStream &operator=(const LoggerStream &) = delete;
template <typename T>
LoggerStream &operator<<(const T &value)
{
ss << value;
return *this;
}
~LoggerStream()
{
logFunc(ss.str());
}
private:
LoggerInterface *logger;
std::function<void(const std::string &)> logFunc;
std::stringstream ss;
};
//class FormatterInterface
//{
//public:
// virtual ~FormatterInterface() = default;
// virtual std::string format(const std::string& fmt, ...) = 0;
//};
//class DefaultFormatter : public FormatterInterface
//{
//public:
// std::string format(const std::string& fmt, ...) override {
// va_list args;
// va_start(args, fmt);
// std::string formatted = LoggerFormatNS::vformat(fmt, fmt::make_format_args(args));
// va_end(args);
// return formatted;
// }
//};
class LoggerSinkInterface {
protected:
std::string m_pattern;
LogLevel m_level;
friend class Logger;
virtual std::any getBaseSink() = 0;
public:
virtual ~LoggerSinkInterface() = default;
virtual void flush() noexcept(false) = 0;
virtual void setPattern(const std::string& pattern) = 0;
virtual std::string pattern() const = 0;
virtual void setLevel(LogLevel level) = 0;
virtual LogLevel level() const = 0;
};
// 预留了两种打印方法的 Sink 实现,要求每个日志系统都要实现这两种 Sink
// 也可以自定义更多 Sink 实现类
class ConsoleLoggerSink : public LoggerSinkInterface {
protected:
virtual std::any getBaseSink();
class Impl;
std::unique_ptr<Impl> pImpl;
LogColorMode m_colorMode;
#ifdef _WIN32
typedef std::uint16_t LogColor;
#else
typedef std::string_view LogColor;
#endif
LogColor m_color;
public:
virtual void flush() noexcept(false);
virtual void setPattern(const std::string& pattern);
virtual std::string pattern() const;
virtual void setLevel(LogLevel level);
virtual LogLevel level() const;
explicit ConsoleLoggerSink(const std::string& name, LogColorMode colorMode = LogColorMode::automatic);
void setColorMode(LogColorMode colorMode);
void setColor(LogLevel level, LogColor colorCode);
//LogColorMode getColorMode() const;
//std::string_view getColor(LogLevel level) const;
};
class FileLoggerSink : public LoggerSinkInterface {
protected:
virtual std::any getBaseSink();
class Impl;
std::unique_ptr<Impl> pImpl;
public:
struct FileEventHandler {
std::function<void(const std::string& filename)> beforeOpen = nullptr;
std::function<void(const std::string& filename, std::FILE* fileStream)> afterOpen = nullptr;
std::function<void(const std::string& filename, std::FILE* fileStream)> beforeClose = nullptr;
std::function<void(const std::string& filename)> afterClose = nullptr;
};
explicit FileLoggerSink(const std::string& name, bool truncate = false, FileEventHandler eventHandler = FileEventHandler());
virtual void flush() noexcept(false) = 0;
virtual void setPattern(const std::string& pattern);
virtual std::string pattern() const;
virtual void setLevel(LogLevel level);
virtual LogLevel level() const;
};
// 日志打印器接口
class LoggerInterface
{
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 LoggerStream trace() noexcept = 0;
virtual LoggerStream debug() noexcept = 0;
virtual LoggerStream info() noexcept = 0;
virtual LoggerStream warning() noexcept = 0;
virtual LoggerStream error() noexcept = 0;
virtual LoggerStream critical() noexcept = 0;
virtual void trace(const std::string &msg) noexcept = 0;
virtual void debug(const std::string &msg) noexcept = 0;
virtual void info(const std::string &msg) noexcept = 0;
virtual void warning(const std::string &msg) noexcept = 0;
virtual void error(const std::string &msg) noexcept = 0;
virtual void critical(const std::string &msg) noexcept = 0;
// 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);
}
};
// 错误码
typedef int LoggerErrorCodeType;
enum class LoggerErrorCode : LoggerErrorCodeType
{
OK = 0,
Unknown = 1,
SinkNotInitialized = 2,
PatternSetFailed = 3,
};
// 自定义日志抛出的错误
class LoggerException : public std::exception
{
private:
std::string msg;
LoggerErrorCode eCode;
public:
explicit LoggerException(LoggerErrorCode code, const std::string& message) : std::exception(message.c_str()), msg(message), eCode(code) {}
char const* what() const override {
return this->msg.c_str();
}
LoggerErrorCode code() const {
return this->eCode;
}
std::string toString() const {
return msg;
}
LoggerErrorCodeType toLoggerErrorCodeType() const {
return static_cast<LoggerErrorCodeType>(eCode);
}
operator std::string() const {
return msg;
}
operator LoggerErrorCode() const {
return eCode;
}
operator LoggerErrorCodeType() const {
return static_cast<LoggerErrorCodeType>(eCode);
}
};
// 日志打印器
class Logger : public LoggerInterface
{
private:
class LoggerImpl;
std::unique_ptr<LoggerImpl> pImpl;
public:
// 默认构造仅使用ConsoleLoggerSink
explicit Logger(const std::string &name);
// 带有自定义 Sink 列表的构造函数
template <typename SinksIterator>
explicit Logger(const std::string &name, SinksIterator&& sinksBegin, SinksIterator&& sinksEnd);
explicit Logger(const std::string &name, std::vector<std::shared_ptr<LoggerSinkInterface>> sinks)
: Logger(name, sinks.begin(), sinks.end()) {}
~Logger();
void setGlobalLevel(LogLevel level) noexcept(false) override;
void setLevel(LogLevel level) noexcept(false) override;
// 流式日志打印
LoggerStream trace() noexcept override;
LoggerStream debug() noexcept override;
LoggerStream info() noexcept override;
LoggerStream warning() noexcept override;
LoggerStream error() noexcept override;
LoggerStream critical() noexcept override;
void trace(const std::string &msg) noexcept override;
void debug(const std::string &msg) noexcept override;
void info(const std::string &msg) noexcept override;
void warning(const std::string &msg) noexcept override;
void error(const std::string &msg) noexcept override;
void critical(const std::string &msg) noexcept override;
};
#endif // !LOGGER_H

View File

@@ -0,0 +1,36 @@
#include <Logger.h>
// 流传递无参日志打印
LoggerStream Logger::trace() noexcept
{
return LoggerStream(this, [this](const std::string& msg) { this->trace(msg); });
}
LoggerStream Logger::debug() noexcept
{
return LoggerStream(this, [this](const std::string& msg) { this->debug(msg); });
}
LoggerStream Logger::info() noexcept
{
return LoggerStream(this, [this](const std::string& msg) { this->info(msg); });
}
LoggerStream Logger::warning() noexcept
{
return LoggerStream(this, [this](const std::string& msg) { this->warning(msg); });
}
LoggerStream Logger::error() noexcept
{
return LoggerStream(this, [this](const std::string& msg) { this->error(msg); });
}
LoggerStream Logger::critical() noexcept
{
return LoggerStream(this, [this](const std::string& msg) { this->critical(msg); });
}
#ifdef USE_SPDLOG
#include "LoggerSpdLog.h"
#endif

View File

@@ -0,0 +1,320 @@
#pragma once
#include <Logger.h>
//#include "../include/Logger.h"
//#include "../../../vcpkg_installed/x64-windows/include/spdlog/spdlog.h"
//#include "../../../vcpkg_installed/x64-windows/include/spdlog/sinks/sink.h"
//#include "../../../vcpkg_installed/x64-windows/include/spdlog/sinks/stdout_color_sinks.h"
#include <spdlog/spdlog.h>
#include <spdlog/sinks/stdout_color_sinks.h>
#include <spdlog/sinks/basic_file_sink.h>
#include <any>
class SpdLogUtils {
public:
enum class SpdLogLevel : int
{
trace = SPDLOG_LEVEL_TRACE,
debug = SPDLOG_LEVEL_DEBUG,
info = SPDLOG_LEVEL_INFO,
warning = SPDLOG_LEVEL_WARN,
error = SPDLOG_LEVEL_ERROR,
critical = SPDLOG_LEVEL_CRITICAL,
off = SPDLOG_LEVEL_OFF
};
static SpdLogLevel logLevelToSpdLogLevel(LogLevel level) {
SpdLogLevel spdLevel = SpdLogLevel::trace;
switch (level)
{
case LogLevel::trace:
spdLevel = SpdLogLevel::trace;
break;
case LogLevel::debug:
spdLevel = SpdLogLevel::debug;
break;
case LogLevel::info:
spdLevel = SpdLogLevel::info;
break;
case LogLevel::warning:
spdLevel = SpdLogLevel::warning;
break;
case LogLevel::error:
spdLevel = SpdLogLevel::error;
break;
case LogLevel::critical:
spdLevel = SpdLogLevel::critical;
break;
case LogLevel::off:
spdLevel = SpdLogLevel::off;
break;
default:
spdLevel = SpdLogLevel::trace;
break;
}
return spdLevel;
}
typedef spdlog::color_mode SpdLogColorMode;
static SpdLogColorMode logColorModeToSpdLogColorMode(LogColorMode colorMode) {
SpdLogColorMode cm = SpdLogColorMode::automatic;
switch (colorMode)
{
case LogColorMode::automatic:
cm = SpdLogColorMode::automatic;
break;
case LogColorMode::always:
cm = SpdLogColorMode::always;
break;
case LogColorMode::never:
cm = SpdLogColorMode::never;
break;
default:
break;
}
return cm;
}
};
class ConsoleLoggerSink::Impl {
private:
public:
// spdlog sink
std::shared_ptr<spdlog::sinks::stdout_color_sink_mt> m_sink;
Impl(LogColorMode colorMode = LogColorMode::automatic)
: m_sink(std::make_shared<spdlog::sinks::stdout_color_sink_mt>()) {
SpdLogUtils::SpdLogColorMode cm = SpdLogUtils::logColorModeToSpdLogColorMode(colorMode);
m_sink->set_color_mode(cm);
}
operator spdlog::sinks::sink& () {
return *m_sink;
}
};
ConsoleLoggerSink::ConsoleLoggerSink(const std::string& name, LogColorMode colorMode)
: pImpl(std::make_unique<Impl>(colorMode)), m_colorMode(colorMode) {}
std::any ConsoleLoggerSink::getBaseSink()
{
return std::any(pImpl->m_sink);
}
void ConsoleLoggerSink::flush() noexcept(false) {
pImpl->m_sink->flush();
}
void ConsoleLoggerSink::setPattern(const std::string& pattern) {
if (pImpl->m_sink)
{
try {
pImpl->m_sink->set_pattern(pattern);
m_pattern = pattern;
}
catch (const spdlog::spdlog_ex& ex)
{
throw LoggerException(LoggerErrorCode::PatternSetFailed, "Failed to set log pattern: " + std::string(ex.what()));
}
}
else
throw LoggerException(LoggerErrorCode::SinkNotInitialized, "Sink is not initialized.");
}
std::string ConsoleLoggerSink::pattern() const {
return m_pattern;
}
void ConsoleLoggerSink::setLevel(LogLevel level) {
if (pImpl->m_sink)
{
pImpl->m_sink->set_level(static_cast<spdlog::level::level_enum>(SpdLogUtils::logLevelToSpdLogLevel(level)));
m_level = level;
}
else
throw LoggerException(LoggerErrorCode::SinkNotInitialized, "Sink is not initialized.");
}
LogLevel ConsoleLoggerSink::level() const {
return m_level;
}
void ConsoleLoggerSink::setColorMode(LogColorMode colorMode) {
m_colorMode = colorMode;
}
void ConsoleLoggerSink::setColor(LogLevel level, LogColor colorCode) {
// 设置不同日志级别的颜色代码
if (pImpl->m_sink)
{
pImpl->m_sink->set_color(static_cast<spdlog::level::level_enum>(SpdLogUtils::logLevelToSpdLogLevel(level)), colorCode);
m_color = colorCode;
}
else
throw LoggerException(LoggerErrorCode::SinkNotInitialized, "Sink is not initialized.");
}
class FileLoggerSink::Impl {
private:
public:
// spdlog sink
std::shared_ptr<spdlog::sinks::basic_file_sink_mt> m_sink;
Impl(const std::string& filePath, bool truncate, FileEventHandler evh) {
spdlog::file_event_handlers feh;
feh.before_open = evh.beforeOpen;
feh.after_open = evh.afterOpen;
feh.before_close = evh.beforeClose;
feh.after_close = evh.afterClose;
m_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>(filePath, truncate, feh);
}
operator spdlog::sinks::sink&() {
return *m_sink;
}
};
FileLoggerSink::FileLoggerSink(const std::string& name, bool truncate, FileEventHandler eventHandler)
: pImpl(std::make_unique<Impl>(name, truncate, eventHandler)) {}
std::any FileLoggerSink::getBaseSink()
{
return std::any(pImpl->m_sink);
}
void FileLoggerSink::flush() noexcept(false) {
pImpl->m_sink->flush();
}
void FileLoggerSink::setPattern(const std::string& pattern) {
if (pImpl->m_sink)
{
try {
pImpl->m_sink->set_pattern(pattern);
m_pattern = pattern;
}
catch (const spdlog::spdlog_ex& ex)
{
throw LoggerException(LoggerErrorCode::PatternSetFailed, "Failed to set log pattern: " + std::string(ex.what()));
}
}
else
throw LoggerException(LoggerErrorCode::SinkNotInitialized, "Sink is not initialized.");
}
std::string FileLoggerSink::pattern() const {
return m_pattern;
}
void FileLoggerSink::setLevel(LogLevel level) {
if (pImpl->m_sink)
{
pImpl->m_sink->set_level(static_cast<spdlog::level::level_enum>(SpdLogUtils::logLevelToSpdLogLevel(level)));
m_level = level;
}
else
throw LoggerException(LoggerErrorCode::SinkNotInitialized, "Sink is not initialized.");
}
LogLevel FileLoggerSink::level() const {
return m_level;
}
class Logger::LoggerImpl {
private:
public:
std::shared_ptr<spdlog::logger> logger;
LoggerImpl(const std::string& name) {
logger = spdlog::get(name);
if (!logger)
{
logger = spdlog::stdout_color_mt(name);
}
}
template <typename SinksIterator>
LoggerImpl(const std::string& name, SinksIterator&& begin, SinksIterator&& end) {
std::vector< std::shared_ptr<spdlog::sinks::sink>> sinks;
for (auto it = begin; it != end; ++it) {
auto sinkSharedPtr = (*it)->getBaseSink();
sinks.push_back(std::any_cast<std::shared_ptr<spdlog::sinks::sink>> (sinkSharedPtr));
}
logger = std::make_shared<spdlog::logger>(name, sinks.begin(), sinks.end());
if (logger)
spdlog::register_logger(logger);
}
~LoggerImpl() {
try {
logger->flush();
}
catch (...) {}
try {
spdlog::drop(logger->name());
}
catch (...) {}
}
};
Logger::Logger(const std::string &name) : pImpl(std::make_unique<Logger::LoggerImpl>(name))
{
}
template <typename SinksIterator>
Logger::Logger(const std::string& name, SinksIterator&& sinksBegin, SinksIterator&& sinksEnd)
: pImpl(std::make_unique<Logger::LoggerImpl>(name, std::forward<SinksIterator>(sinksBegin), std::forward<SinksIterator>(sinksEnd)))
{
}
Logger::~Logger()
{
}
void Logger::setGlobalLevel(LogLevel level) noexcept(false)
{
SpdLogUtils::SpdLogLevel l = SpdLogUtils::logLevelToSpdLogLevel(level);
spdlog::set_level(static_cast<spdlog::level::level_enum>(l));
}
void Logger::setLevel(LogLevel level) noexcept(false)
{
if (pImpl->logger)
{
SpdLogUtils::SpdLogLevel l = SpdLogUtils::logLevelToSpdLogLevel(level);
pImpl->logger->set_level(static_cast<spdlog::level::level_enum>(l));
}
}
// 带参数日志打印
void Logger::trace(const std::string &msg) noexcept
{
if (pImpl->logger)
{
pImpl->logger->trace(msg);
}
}
void Logger::debug(const std::string &msg) noexcept
{
if (pImpl->logger)
{
pImpl->logger->debug(msg);
}
}
void Logger::info(const std::string &msg) noexcept
{
if (pImpl->logger)
{
pImpl->logger->info(msg);
}
}
void Logger::warning(const std::string &msg) noexcept
{
if (pImpl->logger)
{
pImpl->logger->warn(msg);
}
}
void Logger::error(const std::string &msg) noexcept
{
if (pImpl->logger)
{
pImpl->logger->error(msg);
}
}
void Logger::critical(const std::string &msg) noexcept
{
if (pImpl->logger)
{
pImpl->logger->critical(msg);
}
}

View File

@@ -0,0 +1,118 @@
#include "StringProcess.h"
#include <Windows.h>
std::string wstr2str_2UTF8(std::wstring text)
{
CHAR* str;
int Tsize = WideCharToMultiByte(CP_UTF8, 0, text.c_str(), -1, 0, 0, 0, 0);
str = new CHAR[Tsize];
WideCharToMultiByte(CP_UTF8, 0, text.c_str(), -1, str, Tsize, 0, 0);
std::string str1 = str;
delete[]str;
return str1;
}
std::string wstr2str_2ANSI(std::wstring text)
{
CHAR* str;
int Tsize = WideCharToMultiByte(CP_ACP, 0, text.c_str(), -1, 0, 0, 0, 0);
str = new CHAR[Tsize];
WideCharToMultiByte(CP_ACP, 0, text.c_str(), -1, str, Tsize, 0, 0);
std::string str1 = str;
delete[]str;
return str1;
}
std::wstring str2wstr_2UTF8(std::string text)
{
WCHAR* str;
int Tsize = MultiByteToWideChar(CP_UTF8, 0, text.c_str(), -1, 0, 0);
str = new WCHAR[Tsize];
MultiByteToWideChar(CP_UTF8, 0, text.c_str(), -1, str, Tsize);
std::wstring str1 = str;
delete[]str;
return str1;
}
std::wstring str2wstr_2ANSI(std::string text)
{
WCHAR* str;
int Tsize = MultiByteToWideChar(CP_ACP, 0, text.c_str(), -1, 0, 0);
str = new WCHAR[Tsize];
MultiByteToWideChar(CP_ACP, 0, text.c_str(), -1, str, Tsize);
std::wstring str1 = str;
delete[]str;
return str1;
}
std::string UTF8ToANSI(std::string utf8Text)
{
WCHAR* wstr;//中间量
CHAR* str;//转换后的
int Tsize = MultiByteToWideChar(CP_UTF8, 0, utf8Text.c_str(), -1, 0, 0);
wstr = new WCHAR[Tsize];
MultiByteToWideChar(CP_UTF8, 0, utf8Text.c_str(), -1, wstr, Tsize);
Tsize = WideCharToMultiByte(CP_ACP, 0, wstr, -1, 0, 0, 0, 0);
str = new CHAR[Tsize];
WideCharToMultiByte(CP_ACP, 0, wstr, -1, str, Tsize, 0, 0);
std::string wstr1 = str;
delete[]str;
delete[]wstr;
return wstr1;
}
std::string ANSIToUTF8(std::string ansiText)
{
WCHAR* wstr;//中间量
CHAR* str;//转换后的
int Tsize = MultiByteToWideChar(CP_ACP, 0, ansiText.c_str(), -1, 0, 0);
wstr = new WCHAR[Tsize];
MultiByteToWideChar(CP_ACP, 0, ansiText.c_str(), -1, wstr, Tsize);
Tsize = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, 0, 0, 0, 0);
str = new CHAR[Tsize];
WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, Tsize, 0, 0);
std::string wstr1 = str;
delete[]str;
delete[]wstr;
return wstr1;
}
std::wstring ANSIToUTF8(std::wstring ansiText)
{
CHAR* str;//中间量
WCHAR* wstr;//转换后的
int Tsize = WideCharToMultiByte(CP_ACP, 0, ansiText.c_str(), -1, 0, 0, 0, 0);
str = new CHAR[Tsize];
WideCharToMultiByte(CP_ACP, 0, ansiText.c_str(), -1, str, Tsize, 0, 0);
Tsize = MultiByteToWideChar(CP_UTF8, 0, str, -1, 0, 0);
wstr = new WCHAR[Tsize];
MultiByteToWideChar(CP_UTF8, 0, str, -1, wstr, Tsize);
std::wstring wstr1 = wstr;
delete[]str;
delete[]wstr;
return wstr1;
}
std::wstring UTF8ToANSI(std::wstring utf8Text)
{
CHAR* str;//中间量
WCHAR* wstr;//转换后的
int Tsize = WideCharToMultiByte(CP_UTF8, 0, utf8Text.c_str(), -1, 0, 0, 0, 0);
str = new CHAR[Tsize];
WideCharToMultiByte(CP_UTF8, 0, utf8Text.c_str(), -1, str, Tsize, 0, 0);
Tsize = MultiByteToWideChar(CP_ACP, 0, str, -1, 0, 0);
wstr = new WCHAR[Tsize];
MultiByteToWideChar(CP_ACP, 0, str, -1, wstr, Tsize);
std::wstring wstr1 = wstr;
delete[]str;
delete[]wstr;
return wstr1;
}
std::wstring boolToWString(bool Bool)
{
return (Bool ? L"true" : L"false");
}
std::string boolToString(bool Bool)
{
return (Bool ? "true" : "false");
}

View File

@@ -0,0 +1,131 @@
#pragma once
#include <string>
#include <vector>
inline std::string wstr2str_2UTF8(std::wstring text);
inline std::string wstr2str_2ANSI(std::wstring text);
inline std::wstring str2wstr_2UTF8(std::string text);
inline std::wstring str2wstr_2ANSI(std::string text);
inline std::string UTF8ToANSI(std::string utf8Text);
inline std::string ANSIToUTF8(std::string ansiText);
inline std::wstring ANSIToUTF8(std::wstring ansiText);
inline std::wstring UTF8ToANSI(std::wstring utf8Text);
inline std::wstring boolToWString(bool Bool);
inline std::string boolToString(bool Bool);
#include <Windows.h>
inline std::string wstr2str_2UTF8(std::wstring text)
{
CHAR *str;
int Tsize = WideCharToMultiByte(CP_UTF8, 0, text.c_str(), -1, 0, 0, 0, 0);
str = new CHAR[Tsize];
WideCharToMultiByte(CP_UTF8, 0, text.c_str(), -1, str, Tsize, 0, 0);
std::string str1 = str;
delete[] str;
return str1;
}
inline std::string wstr2str_2ANSI(std::wstring text)
{
CHAR *str;
int Tsize = WideCharToMultiByte(CP_ACP, 0, text.c_str(), -1, 0, 0, 0, 0);
str = new CHAR[Tsize];
WideCharToMultiByte(CP_ACP, 0, text.c_str(), -1, str, Tsize, 0, 0);
std::string str1 = str;
delete[] str;
return str1;
}
inline std::wstring str2wstr_2UTF8(std::string text)
{
WCHAR *str;
int Tsize = MultiByteToWideChar(CP_UTF8, 0, text.c_str(), -1, 0, 0);
str = new WCHAR[Tsize];
MultiByteToWideChar(CP_UTF8, 0, text.c_str(), -1, str, Tsize);
std::wstring str1 = str;
delete[] str;
return str1;
}
inline std::wstring str2wstr_2ANSI(std::string text)
{
WCHAR *str;
int Tsize = MultiByteToWideChar(CP_ACP, 0, text.c_str(), -1, 0, 0);
str = new WCHAR[Tsize];
MultiByteToWideChar(CP_ACP, 0, text.c_str(), -1, str, Tsize);
std::wstring str1 = str;
delete[] str;
return str1;
}
inline std::string UTF8ToANSI(std::string utf8Text)
{
WCHAR *wstr; // 中间量
CHAR *str; // 转换后的
int Tsize = MultiByteToWideChar(CP_UTF8, 0, utf8Text.c_str(), -1, 0, 0);
wstr = new WCHAR[Tsize];
MultiByteToWideChar(CP_UTF8, 0, utf8Text.c_str(), -1, wstr, Tsize);
Tsize = WideCharToMultiByte(CP_ACP, 0, wstr, -1, 0, 0, 0, 0);
str = new CHAR[Tsize];
WideCharToMultiByte(CP_ACP, 0, wstr, -1, str, Tsize, 0, 0);
std::string wstr1 = str;
delete[] str;
delete[] wstr;
return wstr1;
}
inline std::string ANSIToUTF8(std::string ansiText)
{
WCHAR *wstr; // 中间量
CHAR *str; // 转换后的
int Tsize = MultiByteToWideChar(CP_ACP, 0, ansiText.c_str(), -1, 0, 0);
wstr = new WCHAR[Tsize];
MultiByteToWideChar(CP_ACP, 0, ansiText.c_str(), -1, wstr, Tsize);
Tsize = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, 0, 0, 0, 0);
str = new CHAR[Tsize];
WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, Tsize, 0, 0);
std::string wstr1 = str;
delete[] str;
delete[] wstr;
return wstr1;
}
inline std::wstring ANSIToUTF8(std::wstring ansiText)
{
CHAR *str; // 中间量
WCHAR *wstr; // 转换后的
int Tsize = WideCharToMultiByte(CP_ACP, 0, ansiText.c_str(), -1, 0, 0, 0, 0);
str = new CHAR[Tsize];
WideCharToMultiByte(CP_ACP, 0, ansiText.c_str(), -1, str, Tsize, 0, 0);
Tsize = MultiByteToWideChar(CP_UTF8, 0, str, -1, 0, 0);
wstr = new WCHAR[Tsize];
MultiByteToWideChar(CP_UTF8, 0, str, -1, wstr, Tsize);
std::wstring wstr1 = wstr;
delete[] str;
delete[] wstr;
return wstr1;
}
inline std::wstring UTF8ToANSI(std::wstring utf8Text)
{
CHAR *str; // 中间量
WCHAR *wstr; // 转换后的
int Tsize = WideCharToMultiByte(CP_UTF8, 0, utf8Text.c_str(), -1, 0, 0, 0, 0);
str = new CHAR[Tsize];
WideCharToMultiByte(CP_UTF8, 0, utf8Text.c_str(), -1, str, Tsize, 0, 0);
Tsize = MultiByteToWideChar(CP_ACP, 0, str, -1, 0, 0);
wstr = new WCHAR[Tsize];
MultiByteToWideChar(CP_ACP, 0, str, -1, wstr, Tsize);
std::wstring wstr1 = wstr;
delete[] str;
delete[] wstr;
return wstr1;
}
inline std::wstring boolToWString(bool Bool)
{
return (Bool ? L"true" : L"false");
}
inline std::string boolToString(bool Bool)
{
return (Bool ? "true" : "false");
}

View File

@@ -18,191 +18,191 @@ namespace Vivid2D::Render::Texture
class Texture;
}
// <EFBFBD><EFBFBD>ǰ<EFBFBD><EFBFBD><EFBFBD><EFBFBD> spdlog::logger <EFBFBD>Ա<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͷ<EFBFBD>ļ<EFBFBD><EFBFBD>а<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
// 向前声明 spdlog::logger 以避免在头文件中包含其完整定义
namespace spdlog {
class logger;
}
/**
* @class RenderSystem
* @brief <EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD>̰߳<EFBFBD>ȫ<EFBFBD>ġ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>е<EFBFBD> OpenGL API <EFBFBD><EFBFBD>װ<EFBFBD>
* @brief 提供一个线程安全的、基于命令队列的 OpenGL API 封装层。
* @details
* <EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȫ<EFBFBD><EFBFBD>̬<EFBFBD><EFBFBD><EFBFBD>ּ࣬<EFBFBD>ڽ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>κ<EFBFBD><EFBFBD>̵߳<EFBFBD><EFBFBD><EFBFBD>Ⱦ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ŷӣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD>ר<EFBFBD>õ<EFBFBD><EFBFBD><EFBFBD>Ⱦ<EFBFBD>߳<EFBFBD><EFBFBD><EFBFBD>ִ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǡ<EFBFBD>
* <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȷ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> OpenGL <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>̰߳<DFB3>ȫ<EFBFBD>ԡ<EFBFBD><D4A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>˶<EFBFBD> OpenGL ״̬<D7B4><CCAC><EFBFBD><EFBFBD>ɫ<EFBFBD><C9AB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* <EFBFBD>߼<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ܣ<EFBFBD><EFBFBD>Լ<EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڵ<EFBFBD><EFBFBD>ԵĴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ơ<EFBFBD>
* ʹ<EFBFBD>÷<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>̻߳<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߼<EFBFBD><EFBFBD>߳<EFBFBD><EFBFBD>е<EFBFBD><EFBFBD>ù<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ľ<EFBFBD>̬<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> RenderSystem::drawElements<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* <EFBFBD><EFBFBD>Щ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ⱦ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>¼<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>С<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ⱦ<EFBFBD>̵߳<EFBFBD>ѭ<EFBFBD><EFBFBD><EFBFBD>У<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> RenderSystem::replayQueue()
* <EFBFBD><EFBFBD>ִ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ŷӵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* 这是一个完全静态的类,旨在将来自任何线程的渲染调用排队,并在一个专用的渲染线程上执行它们。
* 这样做可以确保所有 OpenGL 操作的线程安全性。它还提供了对 OpenGL 状态、着色器、缓冲区和纹理的
* 高级管理功能,以及一个用于调试的错误检查机制。
* 使用方法:在主线程或其他逻辑线程中调用公开的静态方法(如 RenderSystem::drawElements
* 这些方法会将渲染命令记录到队列中。在渲染线程的循环中,调用 RenderSystem::replayQueue()
* 来执行所有排队的命令。
*/
class VIVID_2D_MYDLL_API RenderSystem {
public:
// RenderSystem <EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>̬<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>˽<EFBFBD>ֹʵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
// RenderSystem 是一个静态工具类,因此禁止实例化。
RenderSystem() = delete;
~RenderSystem() = delete;
RenderSystem(const RenderSystem&) = delete;
RenderSystem& operator=(const RenderSystem&) = delete;
using GLADloader = void* (*)(const char* name);
// ================== <EFBFBD><EFBFBD>־ϵͳ<EFBFBD><EFBFBD><EFBFBD><EFBFBD> ==================
// ================== 日志系统管理 ==================
/**
* @brief <EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>־ϵͳ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>κ<EFBFBD><EFBFBD><EFBFBD>־<EFBFBD><EFBFBD><EFBFBD><EFBFBD>֮ǰ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʼʱ<EFBFBD><EFBFBD><EFBFBD>á<EFBFBD>
* @brief 初始化日志系统。必须在任何日志调用之前,在主函数开始时调用。
*/
static void InitializeLogging();
/**
* @brief <EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD>־ϵͳ<EFBFBD><EFBFBD>Ӧ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȷ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>־<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ˢ<EFBFBD>¡<EFBFBD>
* @brief 关闭日志系统。应在主函数结束时调用以确保所有日志都被刷新。
*/
static void ShutdownLogging();
// ================== <EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>̹߳<EFBFBD><EFBFBD><EFBFBD> ==================
// ================== 初始化与线程管理 ==================
/**
* @brief <EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ר<EFBFBD>õ<EFBFBD><EFBFBD><EFBFBD>Ⱦ<EFBFBD>̡߳<EFBFBD>
* @brief 初始化并启动专用的渲染线程。
*/
static void initRenderThread();
/**
* @brief <EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD>Ⱦϵͳ<EFBFBD>ij<EFBFBD>ʼ<EFBFBD><EFBFBD><EFBFBD>׶Ρ<EFBFBD><EFBFBD>ڴ˽׶Σ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ÿ<EFBFBD><EFBFBD><EFBFBD>ֱ<EFBFBD><EFBFBD><EFBFBD>ڵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>߳<EFBFBD><EFBFBD><EFBFBD>ִ<EFBFBD>С<EFBFBD>
* @brief 开始渲染系统的初始化阶段。在此阶段,调用可以直接在调用线程上执行。
*/
static void beginInitialization();
/**
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ⱦϵͳ<EFBFBD>ij<EFBFBD>ʼ<EFBFBD><EFBFBD><EFBFBD>׶Ρ<EFBFBD><EFBFBD>˺<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>е<EFBFBD><EFBFBD>ö<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ŷӡ<EFBFBD>
* @brief 结束渲染系统的初始化阶段。此后,所有调用都将被排队。
*/
static void finishInitialization();
/**
* @brief <EFBFBD><EFBFBD><EFBFBD>鵱ǰ<EFBFBD>߳<EFBFBD><EFBFBD>Ƿ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ⱦ<EFBFBD>̡߳<EFBFBD>
* @return <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ⱦ<EFBFBD>̣߳<EFBFBD><EFBFBD>򷵻<EFBFBD> true<EFBFBD><EFBFBD>
* @brief 检查当前线程是否是渲染线程。
* @return 如果是渲染线程,则返回 true
*/
static bool isOnRenderThread();
/**
* @brief <EFBFBD><EFBFBD><EFBFBD>鵱ǰ<EFBFBD>Ƿ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڳ<EFBFBD>ʼ<EFBFBD><EFBFBD><EFBFBD>׶Ρ<EFBFBD>
* @return <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>dz<EFBFBD>ʼ<EFBFBD><EFBFBD><EFBFBD>׶Σ<EFBFBD><EFBFBD>򷵻<EFBFBD> true<EFBFBD><EFBFBD>
* @brief 检查当前是否处于初始化阶段。
* @return 如果是初始化阶段,则返回 true
*/
static bool isInInitPhase();
/**
* @brief <EFBFBD><EFBFBD><EFBFBD>Ե<EFBFBD>ǰ<EFBFBD>̱߳<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ⱦ<EFBFBD>̣߳<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֹ<EFBFBD><EFBFBD>
* @brief 断言当前线程必须是渲染线程,否则程序将中止。
*/
static void assertOnRenderThread();
/**
* @brief <EFBFBD><EFBFBD><EFBFBD>Ե<EFBFBD>ǰ<EFBFBD>̱߳<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ⱦ<EFBFBD>̻߳<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڳ<EFBFBD>ʼ<EFBFBD><EFBFBD><EFBFBD>׶Ρ<EFBFBD>
* @brief 断言当前线程必须是渲染线程或处于初始化阶段。
*/
static void assertOnRenderThreadOrInit();
/**
* @brief ʹ<EFBFBD><EFBFBD> GLAD <EFBFBD><EFBFBD><EFBFBD><EFBFBD> OpenGL <EFBFBD><EFBFBD><EFBFBD><EFBFBD>ָ<EFBFBD>
* @param loader һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ָ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڻ<EFBFBD>ȡ OpenGL <20><><EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD>ַ<EFBFBD><D6B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD> glfwGetProcAddress<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @brief 使用 GLAD 加载 OpenGL 函数指针。
* @param loader 一个函数指针,用于获取 OpenGL 函数的地址(例如 glfwGetProcAddress)。
*/
static void loadGLFunctions(GLADloader loader);
// ================== <EFBFBD><EFBFBD>Ⱦ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ==================
// ================== 渲染命令队列 ==================
/**
* @brief <EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ⱦ<EFBFBD><EFBFBD><EFBFBD>ã<EFBFBD><EFBFBD><EFBFBD>Ϊ lambda <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>¼<EFBFBD><C2BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>У<EFBFBD><D0A3>Ա<EFBFBD><D4B1>Ժ<EFBFBD><D4BA><EFBFBD><EFBFBD><EFBFBD>Ⱦ<EFBFBD>߳<EFBFBD><DFB3><EFBFBD>ִ<EFBFBD>С<EFBFBD>
* @param renderCall Ҫִ<EFBFBD>е<EFBFBD><EFBFBD><EFBFBD>Ⱦ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @brief 将一个渲染调用(作为 lambda 函数)记录到命令队列中,以便稍后在渲染线程上执行。
* @param renderCall 要执行的渲染操作。
*/
static void recordRenderCall(std::function<void()>&& renderCall);
/**
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ⱦ<EFBFBD>߳<EFBFBD><EFBFBD><EFBFBD>ִ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>е<EFBFBD><EFBFBD><EFBFBD><EFBFBD>д<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ⱦ<EFBFBD><EFBFBD><EFBFBD>á<EFBFBD>
* @brief 在渲染线程上执行命令队列中的所有待处理渲染调用。
*/
static void replayQueue();
// ================== OpenGL ״̬<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>װ ==================
// ================== OpenGL 状态管理封装 ==================
/**
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD> OpenGL <EFBFBD><EFBFBD><EFBFBD>ܣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> GL_BLEND<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @param capability Ҫ<EFBFBD><EFBFBD><EFBFBD>õ<EFBFBD> OpenGL <EFBFBD><EFBFBD><EFBFBD><EFBFBD>ö<EFBFBD>١<EFBFBD>
* @brief 启用一个 OpenGL 功能(例如 GL_BLEND)。
* @param capability 要启用的 OpenGL 功能枚举。
*/
static void enable(GLenum capability);
/**
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD> OpenGL <EFBFBD><EFBFBD><EFBFBD>ܡ<EFBFBD>
* @param capability Ҫ<EFBFBD><EFBFBD><EFBFBD>õ<EFBFBD> OpenGL <EFBFBD><EFBFBD><EFBFBD><EFBFBD>ö<EFBFBD>١<EFBFBD>
* @brief 禁用一个 OpenGL 功能。
* @param capability 要禁用的 OpenGL 功能枚举。
*/
static void disable(GLenum capability);
/**
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǰ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ⱦ״̬<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɫ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϡ<EFBFBD><EFBFBD>ӿڵȣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>״̬<EFBFBD><EFBFBD>ջ<EFBFBD><EFBFBD>
* @brief 将当前的渲染状态(如着色器、混合、视口等)推入状态堆栈。
*/
static void pushState();
/**
* @brief <EFBFBD><EFBFBD>״̬<EFBFBD><EFBFBD>ջ<EFBFBD>е<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ָ<EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ⱦ״̬<EFBFBD><EFBFBD>
* @brief 从状态堆栈中弹出并恢复上一个渲染状态。
*/
static void popState();
/**
* @brief <EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD>ǰ״̬<EFBFBD><EFBFBD>ջ<EFBFBD>Ĵ<EFBFBD>С<EFBFBD><EFBFBD>
* @return <EFBFBD><EFBFBD>ջ<EFBFBD>е<EFBFBD>״̬<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @brief 获取当前状态堆栈的大小。
* @return 堆栈中的状态数量。
*/
static size_t getStateStackSize();
/**
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɫ<EFBFBD><EFBFBD>
* @brief 设置清屏颜色。
*/
static void clearColor(float r, float g, float b, float a);
/**
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD>ָ<EFBFBD><EFBFBD><EFBFBD>Ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> GL_COLOR_BUFFER_BIT<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @param mask Ҫ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @brief 清除指定的缓冲区(例如 GL_COLOR_BUFFER_BIT)。
* @param mask 要清除的缓冲区的位域掩码。
*/
static void clear(GLbitfield mask);
/**
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD> OpenGL <EFBFBD>ӿڡ<EFBFBD>
* @brief 设置 OpenGL 视口。
*/
static void viewport(int x, int y, int width, int height);
// ================== VAO / VBO / EBO <EFBFBD><EFBFBD><EFBFBD><EFBFBD> ==================
// ================== VAO / VBO / EBO 操作 ==================
/**
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> (VAO)<EFBFBD><EFBFBD>
* @return <EFBFBD>´<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> VAO <20>ľ<EFBFBD><C4BE><EFBFBD><EFBFBD><EFBFBD>
* @brief 生成一个顶点数组对象 (VAO)
* @return 新创建的 VAO 的句柄。
*/
static GLuint GenVertexArrays();
/**
* @brief ɾ<EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD> VAO<EFBFBD><EFBFBD>
* @param vao Ҫɾ<EFBFBD><EFBFBD><EFBFBD><EFBFBD> VAO <20>ľ<EFBFBD><C4BE><EFBFBD><EFBFBD><EFBFBD>
* @brief 删除一个 VAO
* @param vao 要删除的 VAO 的句柄。
*/
static void DeleteVertexArrays(GLuint vao);
/**
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD> VAO<EFBFBD><EFBFBD>
* @param vao Ҫ<EFBFBD>󶨵<EFBFBD> VAO <EFBFBD>ľ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @brief 绑定一个 VAO
* @param vao 要绑定的 VAO 的句柄。
*/
static void BindVertexArray(GLuint vao);
/**
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> (VBO/EBO)<EFBFBD><EFBFBD>
* @return <EFBFBD>´<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ľ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @brief 生成一个缓冲区对象 (VBO/EBO)
* @return 新创建的缓冲区的句柄。
*/
static GLuint GenBuffers();
/**
* @brief ɾ<EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @param buffer Ҫɾ<EFBFBD><EFBFBD><EFBFBD>Ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ľ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @brief 删除一个缓冲区对象。
* @param buffer 要删除的缓冲区的句柄。
*/
static void DeleteBuffers(GLuint buffer);
/**
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @param target <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ŀ<EFBFBD><EFBFBD> (<28><><EFBFBD><EFBFBD> GL_ARRAY_BUFFER)<EFBFBD><EFBFBD>
* @param buffer Ҫ<EFBFBD>󶨵Ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ľ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @brief 绑定一个缓冲区对象。
* @param target 缓冲区的目标 (例如 GL_ARRAY_BUFFER)
* @param buffer 要绑定的缓冲区的句柄。
*/
static void BindBuffer(GLenum target, GLuint buffer);
/**
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǰ<EFBFBD>󶨵Ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @param target <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ŀ<EFBFBD>
* @param size <EFBFBD><EFBFBD><EFBFBD>ݵĴ<EFBFBD>С<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֽ<EFBFBD>Ϊ<EFBFBD><EFBFBD>λ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @param data ָ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݵ<EFBFBD>ָ<EFBFBD>
* @param usage <EFBFBD><EFBFBD><EFBFBD>ݵ<EFBFBD>Ԥ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>; (<28><><EFBFBD><EFBFBD> GL_STATIC_DRAW)<EFBFBD><EFBFBD>
* @brief 将数据上传到当前绑定的缓冲区。
* @param target 缓冲区目标。
* @param size 数据的大小(以字节为单位)。
* @param data 指向数据的指针。
* @param usage 数据的预期用途 (例如 GL_STATIC_DRAW)
*/
static void BufferData(GLenum target, GLsizeiptr size, const void* data, GLenum usage);
// ================== Uniform <EFBFBD><EFBFBD><EFBFBD><EFBFBD> ==================
// ================== Uniform 设置 ==================
static void uniform1i(GLint location, int value);
static void uniform1f(GLint location, float value);
static void uniform2f(GLint location, float x, float y);
@@ -217,184 +217,184 @@ public:
static void uniformMatrix4(GLint location, const glm::mat4& matrix, bool transpose = false);
/**
* @brief <EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD>ɫ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> uniform <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD>á<EFBFBD>
* @param program <EFBFBD><EFBFBD>ɫ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ľ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @param name uniform <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ơ<EFBFBD>
* @return uniform <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD>á<EFBFBD>
* @brief 获取着色器程序中 uniform 变量的位置。
* @param program 着色器程序的句柄。
* @param name uniform 变量的名称。
* @return uniform 变量的位置。
*/
static GLint getUniformLocation(GLuint program, const std::string& name);
// ================== <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ==================
// ================== 绘制命令 ==================
/**
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߿<EFBFBD><EFBFBD><EFBFBD>
* @brief 设置线宽。
*/
static void lineWidth(float width);
/**
* @brief ʹ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>л<EFBFBD><EFBFBD>ơ<EFBFBD>
* @brief 使用索引进行绘制。
*/
static void drawElements(GLenum mode, GLsizei count, GLenum type, const void* indices);
/**
* @brief ֱ<EFBFBD><EFBFBD>ʹ<EFBFBD>ö<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>л<EFBFBD><EFBFBD>ơ<EFBFBD>
* @brief 直接使用顶点数组进行绘制。
*/
static void drawArrays(GLenum mode, GLint first, GLsizei count);
// ================== <EFBFBD><EFBFBD><EFBFBD><EFBFBD>ģʽ ==================
// ================== 混合模式 ==================
/**
* @brief <EFBFBD><EFBFBD><EFBFBD>û<EFBFBD><EFBFBD>ϡ<EFBFBD>
* @brief 启用混合。
*/
static void enableBlend();
/**
* @brief <EFBFBD><EFBFBD><EFBFBD>û<EFBFBD><EFBFBD>ϡ<EFBFBD>
* @brief 禁用混合。
*/
static void disableBlend();
/**
* @brief <EFBFBD><EFBFBD><EFBFBD>û<EFBFBD><EFBFBD>Ϻ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @brief 设置混合函数。
*/
static void blendFunc(GLenum sfactor, GLenum dfactor);
/**
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĭ<EFBFBD>ϵ<EFBFBD> Alpha <20><><EFBFBD>Ϻ<EFBFBD><CFBA><EFBFBD> (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)<EFBFBD><EFBFBD>
* @brief 设置默认的 Alpha 混合函数 (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
*/
static void defaultBlendFunc();
// ================== <EFBFBD><EFBFBD>ɫ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ==================
// ================== 着色器程序管理 ==================
/**
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD>յ<EFBFBD><EFBFBD><EFBFBD>ɫ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @return <EFBFBD>³<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ľ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @brief 创建一个空的着色器程序。
* @return 新程序的句柄。
*/
static GLuint createProgram();
/**
* @brief <EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD>ǰ<EFBFBD>󶨵<EFBFBD><EFBFBD><EFBFBD>ɫ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @return <EFBFBD><EFBFBD>ǰ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ľ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @brief 获取当前绑定的着色器程序。
* @return 当前程序的句柄。
*/
static GLint getCurrentProgram();
/**
* @brief <EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɫ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӵ<EFBFBD><EFBFBD><EFBFBD>ɫ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @brief 将一个着色器附加到着色器程序。
*/
static void attachShader(GLuint program, GLuint shader);
/**
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɫ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @brief 链接一个着色器程序。
*/
static void linkProgram(GLuint program);
/**
* @brief <EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD>ɫ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>IJ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @brief 获取着色器程序的参数。
*/
static GLint getProgrami(GLuint program, GLenum pname);
/**
* @brief <EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD>ɫ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>־<EFBFBD><EFBFBD>Ϣ<EFBFBD><EFBFBD>
* @brief 获取着色器程序的日志信息。
*/
static std::string getProgramInfoLog(GLuint program);
/**
* @brief <EFBFBD>ӳ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>з<EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɫ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @brief 从程序中分离一个着色器。
*/
static void detachShader(GLuint program, GLuint shader);
/**
* @brief ɾ<EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɫ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @brief 删除一个着色器程序。
*/
static void deleteProgram(GLuint program);
/**
* @brief <EFBFBD><EFBFBD><EFBFBD>Ӷ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɫ<EFBFBD><EFBFBD><EFBFBD>Դ<EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ij<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @brief 链接顶点和片段着色器以创建一个完整的程序。
*/
static GLuint linkProgram(GLuint vertexShader, GLuint fragmentShader);
/**
* @brief <EFBFBD><EFBFBD><EFBFBD>Ӷ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>κ<EFBFBD>Ƭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɫ<EFBFBD><EFBFBD><EFBFBD>Դ<EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ij<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @brief 链接顶点、几何和片段着色器以创建一个完整的程序。
*/
static GLuint linkProgram(GLuint vertexShader, GLuint geometryShader, GLuint fragmentShader);
/**
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɫ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @brief 激活一个着色器程序。
*/
static void useProgram(GLuint program);
// ================== <EFBFBD><EFBFBD>ɫ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ==================
// ================== 着色器管理 ==================
/**
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD>ָ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>͵<EFBFBD><EFBFBD><EFBFBD>ɫ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @param type <EFBFBD><EFBFBD>ɫ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> (<28><><EFBFBD><EFBFBD> GL_VERTEX_SHADER)<EFBFBD><EFBFBD>
* @return <EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɫ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ľ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @brief 创建一个指定类型的着色器对象。
* @param type 着色器类型 (例如 GL_VERTEX_SHADER)
* @return 新着色器对象的句柄。
*/
static GLuint createShader(GLenum type);
/**
* @brief Ϊ<EFBFBD><EFBFBD>ɫ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Դ<EFBFBD><EFBFBD><EFBFBD>
* @brief 为着色器设置源代码。
*/
static void shaderSource(GLuint shader, const std::string& source);
/**
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɫ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @brief 编译一个着色器。
*/
static void compileShader(GLuint shader);
/**
* @brief <EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD>ɫ<EFBFBD><EFBFBD><EFBFBD>IJ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @brief 获取着色器的参数。
*/
static GLint getShaderi(GLuint shader, GLenum pname);
/**
* @brief <EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD>ɫ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>־<EFBFBD><EFBFBD>Ϣ<EFBFBD><EFBFBD>
* @brief 获取着色器的日志信息。
*/
static std::string getShaderInfoLog(GLuint shader);
/**
* @brief ɾ<EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɫ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @brief 删除一个着色器。
*/
static void deleteShader(GLuint shader);
/**
* @brief <EFBFBD><EFBFBD>Դ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD>ָ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>͵<EFBFBD><EFBFBD><EFBFBD>ɫ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @return <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɫ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @brief 从源代码编译一个指定类型的着色器。
* @return 编译后的着色器句柄。
*/
static GLuint compileShader(GLenum type, const std::string& source);
// ================== <EFBFBD><EFBFBD><EFBFBD>Ȳ<EFBFBD><EFBFBD><EFBFBD> ==================
// ================== 深度测试 ==================
static void depthFunc(GLenum func);
static void depthMask(bool flag);
static void clearDepth(double depth);
static void enableDepthTest();
static void disableDepthTest();
// ================== <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ==================
// ================== 纹理管理 ==================
/**
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD> 2D <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǰ<EFBFBD><EFBFBD><EEB6AF><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ԫ<EFBFBD><D4AA>
* @param texture Ҫ<EFBFBD>󶨵<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ľ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @brief 绑定一个 2D 纹理到当前活动的纹理单元。
* @param texture 要绑定的纹理的句柄。
*/
static void bindTexture(GLuint texture);
/**
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD> Texture <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ָ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ԫ<EFBFBD><EFBFBD>
* @details <EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ԫ<EFBFBD>Ͱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϲ<EFBFBD>Ϊһ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* <EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȫ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ⱦ<EFBFBD>̡߳<EFBFBD>
* @param texture Ҫ<EFBFBD>󶨵<EFBFBD> Texture <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ij<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>á<EFBFBD>
* @param textureUnit Ҫ<EFBFBD>󶨵<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ԫ<EFBFBD><EFBFBD><EFBFBD><EFBFBD> (0, 1, 2, ...)<EFBFBD><EFBFBD>
* @brief 绑定一个 Texture 对象到指定的纹理单元。
* @details 这是一个便利方法,它将激活纹理单元和绑定纹理两个操作合并为一个命令,
* 并安全地提交到渲染线程。
* @param texture 要绑定的 Texture 对象的常量引用。
* @param textureUnit 要绑定的纹理单元索引 (0, 1, 2, ...)
*/
static void bindTexture(const Vivid2D::Render::Texture::Texture& texture, int textureUnit = 0);
static void getTexImage(GLenum target, GLint level, GLenum format, GLenum type, void* pixels);
/**
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ԫ<EFBFBD><EFBFBD>
* @param texture Ҫ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ԫ (<28><><EFBFBD><EFBFBD> GL_TEXTURE0)<EFBFBD><EFBFBD>
* @brief 激活一个纹理单元。
* @param texture 要激活的纹理单元 (例如 GL_TEXTURE0)
*/
static void activeTexture(GLenum texture);
/**
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @return <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ľ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @brief 生成一个纹理对象。
* @return 新纹理的句柄。
*/
static GLuint genTextures();
/**
* @brief ɾ<EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @param texture Ҫɾ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ľ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @brief 删除一个纹理对象。
* @param texture 要删除的纹理的句柄。
*/
static void deleteTextures(GLuint texture);
static void texImage2D(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void* pixels);
@@ -405,20 +405,20 @@ public:
static void setTextureWrapT(GLenum wrap);
/**
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD>Ĭ<EFBFBD>ϵ<EFBFBD> 1x1 <20><>ɫ<EFBFBD><C9AB><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @return Ĭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ľ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @brief 创建一个默认的 1x1 白色纹理。
* @return 默认纹理的句柄。
*/
static GLuint createDefaultTexture();
// ================== <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ==================
// ================== 顶点属性 ==================
static void enableVertexAttribArray(GLuint index);
static void disableVertexAttribArray(GLuint index);
static void vertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* pointer);
// ================== <EFBFBD><EFBFBD><EFBFBD>߷<EFBFBD><EFBFBD><EFBFBD> ==================
// ================== 工具方法 ==================
static void readPixels(int x, int y, int width, int height, GLenum format, GLenum type, void* pixels);
/**
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƿ<EFBFBD>֧<EFBFBD><EFBFBD>ij<EFBFBD><EFBFBD> OpenGL <EFBFBD><EFBFBD>չ<EFBFBD><EFBFBD>
* @brief 检查是否支持某个 OpenGL 扩展。
*/
static bool isExtensionSupported(const std::string& extension);
static void pixelStore(GLenum pname, GLint param);
@@ -428,35 +428,35 @@ public:
static std::string getGLSLVersion();
/**
* @brief <EFBFBD><EFBFBD>¼<EFBFBD><EFBFBD>ϸ<EFBFBD><EFBFBD> OpenGL <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϣ<EFBFBD><CFA2>
* @brief 记录详细的 OpenGL 和驱动信息。
*/
static void logDetailedGLInfo();
/**
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD>Ĭ<EFBFBD>ϵ<EFBFBD> OpenGL ״̬<D7B4><CCAC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>û<EFBFBD><C3BB>ϣ<EFBFBD><CFA3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɫ<EFBFBD><C9AB><EFBFBD><EFBFBD>
* @brief 设置一套默认的 OpenGL 状态(例如启用混合,设置清屏色)。
*/
static void setupDefaultState();
/**
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>¼<EFBFBD>κη<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> OpenGL <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @param operation <EFBFBD><EFBFBD><EFBFBD>¼<EFBFBD><EFBFBD><EFBFBD><EFBFBD>IJ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ơ<EFBFBD>
* @brief 检查并记录任何发生的 OpenGL 错误。
* @param operation 导致检查的操作的描述性名称。
*/
static void checkGLError(const std::string& operation);
// ================== <EFBFBD><EFBFBD>ȡ״̬ ==================
// ================== 获取状态 ==================
static int getViewportWidth();
static int getViewportHeight();
static glm::vec4 getClearColor();
/**
* @brief <EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD>ǰ<EFBFBD><EFBFBD>Ⱦ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>е<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @return <EFBFBD><EFBFBD><EFBFBD>д<EFBFBD>С<EFBFBD><EFBFBD>
* @brief 获取当前渲染命令队列中的命令数量。
* @return 队列大小。
*/
static size_t getQueueSize();
private:
struct RenderState;
// ˽<EFBFBD>еġ<EFBFBD>ֱ<EFBFBD><EFBFBD>ִ<EFBFBD><EFBFBD>GL<EFBFBD><EFBFBD><EFBFBD>õİ汾
// 私有的、直接执行GL调用的版本
static void _enable(GLenum capability);
static void _disable(GLenum capability);
static void _pushState();
@@ -511,15 +511,15 @@ private:
static std::string getGLErrorString(GLenum error);
// <EFBFBD><EFBFBD>̬<EFBFBD><EFBFBD>Ա<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
// 静态成员变量
static std::thread::id s_RenderThreadId;
static std::atomic<bool> s_IsInInit;
static std::queue<std::function<void()>> s_RenderQueue;
static std::mutex s_RenderQueueMutex;
static std::atomic<bool> s_IsReplayingQueue;
// ================== RenderState <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʵ<EFBFBD><EFBFBD> ==================
struct RenderSystem::RenderState {
// ================== RenderState 结构体和实现 ==================
struct RenderState {
GLint currentProgram = 0;
GLboolean blendEnabled = GL_FALSE;
GLboolean depthTestEnabled = GL_FALSE;

View File

@@ -0,0 +1,17 @@
#pragma once
#ifndef DEFS_H
#define DEFS_H
//// 检查 VIVID_2D_MYDLL_API 宏是否已经被定义
//#ifdef VIVID_2D_MYDLL_API
//// 如果已经定义,则先取消其定义(防止重复或冲突的定义)
//#undef VIVID_2D_MYDLL_API
//#endif
//
//// 强制将 VIVID_2D_MYDLL_API 宏定义为 __declspec(dllexport)
//// 作用:告诉编译器,使用此宏标记的类、函数或变量,必须从当前 DLL 中导出。
//// 这是在编译 DLL 自身源代码时,确保其接口能够被外部应用程序使用的关键步骤。
//#define VIVID_2D_MYDLL_API __declspec(dllexport)
#endif

View File

@@ -2,6 +2,13 @@
"name": "my-opengl-project",
"version-string": "0.1.0",
"dependencies": [
"stb"
]
"stb",
"glfw3",
"glew",
"glad",
"spdlog",
"glm",
"stduuid"
],
"builtin-baseline": "d1ff36c6520ee43f1a656c03cd6425c2974a449e"
}