diff --git a/.gitignore b/.gitignore index 9491a2f..6cd2c94 100644 --- a/.gitignore +++ b/.gitignore @@ -360,4 +360,6 @@ MigrationBackup/ .ionide/ # Fody - auto-generated XML schema -FodyWeavers.xsd \ No newline at end of file +FodyWeavers.xsd + +**/vcpkg_installed/ diff --git a/README.md b/README.md index 12e9f0a..09418c7 100644 --- a/README.md +++ b/README.md @@ -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 中打开并构建项目。 diff --git a/Vivid2DRenderer/libs/logger/build spdlog.cmd b/Vivid2DRenderer/libs/logger/build spdlog.cmd new file mode 100644 index 0000000..968ebd9 --- /dev/null +++ b/Vivid2DRenderer/libs/logger/build spdlog.cmd @@ -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 \ No newline at end of file diff --git a/Vivid2DRenderer/libs/logger/build/Debugx64/Logger_d.lib b/Vivid2DRenderer/libs/logger/build/Debugx64/Logger_d.lib new file mode 100644 index 0000000..35f6df2 Binary files /dev/null and b/Vivid2DRenderer/libs/logger/build/Debugx64/Logger_d.lib differ diff --git a/Vivid2DRenderer/libs/logger/build/Releasex64/Logger.lib b/Vivid2DRenderer/libs/logger/build/Releasex64/Logger.lib new file mode 100644 index 0000000..6612418 Binary files /dev/null and b/Vivid2DRenderer/libs/logger/build/Releasex64/Logger.lib differ diff --git a/Vivid2DRenderer/libs/logger/include/Logger.h b/Vivid2DRenderer/libs/logger/include/Logger.h new file mode 100644 index 0000000..9684924 --- /dev/null +++ b/Vivid2DRenderer/libs/logger/include/Logger.h @@ -0,0 +1,295 @@ +#pragma once +#ifndef LOGGER_H +#define LOGGER_H + +// C++ 标准库版本判断 +#if __cplusplus >= 202002L && defined(USE_STD_FORMAT) +// C++20 或更高版本 +#include +namespace LoggerFormatNS = std; +#else +#include // 仅基础格式化 +#include // 完整功能 +namespace LoggerFormatNS = fmt; +#endif + +#include +#include +#include +#include +#include + +// 用于支持 << 流式传递打印日志 +// LoggerStream.h +#include +#include +#include + + +// 日志打印等级 +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 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 + LoggerStream &operator<<(const T &value) + { + ss << value; + return *this; + } + + ~LoggerStream() + { + logFunc(ss.str()); + } + +private: + LoggerInterface *logger; + std::function 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 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 pImpl; +public: + struct FileEventHandler { + std::function beforeOpen = nullptr; + std::function afterOpen = nullptr; + std::function beforeClose = nullptr; + std::function 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 + void trace(const std::string &fmt, Args &&...args) noexcept { + _loggerHelper(&LoggerInterface::trace, fmt, std::forward(args)...); + } + template + void debug(const std::string &fmt, Args &&...args) noexcept { + _loggerHelper(&LoggerInterface::debug, fmt, std::forward(args)...); + } + template + void info(const std::string &fmt, Args &&...args) noexcept { + _loggerHelper(&LoggerInterface::info, fmt, std::forward(args)...); + } + template + void warning(const std::string &fmt, Args &&...args) noexcept { + _loggerHelper(&LoggerInterface::warning, fmt, std::forward(args)...); + } + template + void error(const std::string &fmt, Args &&...args) noexcept { + _loggerHelper(&LoggerInterface::error, fmt, std::forward(args)...); + } + template + void critical(const std::string &fmt, Args &&...args) noexcept { + _loggerHelper(&LoggerInterface::critical, fmt, std::forward(args)...); + } + +private: + template + void _loggerHelper(void (LoggerInterface::*func)(const std::string &), const std::string &fmt, Args &&...args) noexcept { + std::string formattedMsg = LoggerFormatNS::format(fmt, std::forward(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(eCode); + } + operator std::string() const { + return msg; + } + operator LoggerErrorCode() const { + return eCode; + } + operator LoggerErrorCodeType() const { + return static_cast(eCode); + } +}; + +// 日志打印器 +class Logger : public LoggerInterface +{ +private: + class LoggerImpl; + std::unique_ptr pImpl; + +public: + // 默认构造:仅使用ConsoleLoggerSink + explicit Logger(const std::string &name); + // 带有自定义 Sink 列表的构造函数 + template + explicit Logger(const std::string &name, SinksIterator&& sinksBegin, SinksIterator&& sinksEnd); + explicit Logger(const std::string &name, std::vector> 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 + diff --git a/Vivid2DRenderer/libs/logger/src/Logger.cpp b/Vivid2DRenderer/libs/logger/src/Logger.cpp new file mode 100644 index 0000000..54b0cab --- /dev/null +++ b/Vivid2DRenderer/libs/logger/src/Logger.cpp @@ -0,0 +1,36 @@ +#include +// 流传递无参日志打印 +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 diff --git a/Vivid2DRenderer/libs/logger/src/LoggerSpdLog.h b/Vivid2DRenderer/libs/logger/src/LoggerSpdLog.h new file mode 100644 index 0000000..3f83e5e --- /dev/null +++ b/Vivid2DRenderer/libs/logger/src/LoggerSpdLog.h @@ -0,0 +1,320 @@ +#pragma once +#include +//#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 +#include +#include +#include + +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 m_sink; + Impl(LogColorMode colorMode = LogColorMode::automatic) + : m_sink(std::make_shared()) { + 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(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(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(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 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(filePath, truncate, feh); + } + operator spdlog::sinks::sink&() { + return *m_sink; + } +}; +FileLoggerSink::FileLoggerSink(const std::string& name, bool truncate, FileEventHandler eventHandler) + : pImpl(std::make_unique(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(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 logger; + LoggerImpl(const std::string& name) { + logger = spdlog::get(name); + if (!logger) + { + logger = spdlog::stdout_color_mt(name); + } + } + template + LoggerImpl(const std::string& name, SinksIterator&& begin, SinksIterator&& end) { + std::vector< std::shared_ptr> sinks; + for (auto it = begin; it != end; ++it) { + auto sinkSharedPtr = (*it)->getBaseSink(); + sinks.push_back(std::any_cast> (sinkSharedPtr)); + } + logger = std::make_shared(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(name)) +{ +} +template +Logger::Logger(const std::string& name, SinksIterator&& sinksBegin, SinksIterator&& sinksEnd) + : pImpl(std::make_unique(name, std::forward(sinksBegin), std::forward(sinksEnd))) +{ + +} + +Logger::~Logger() +{ + +} + + +void Logger::setGlobalLevel(LogLevel level) noexcept(false) +{ + SpdLogUtils::SpdLogLevel l = SpdLogUtils::logLevelToSpdLogLevel(level); + spdlog::set_level(static_cast(l)); +} + +void Logger::setLevel(LogLevel level) noexcept(false) +{ + if (pImpl->logger) + { + SpdLogUtils::SpdLogLevel l = SpdLogUtils::logLevelToSpdLogLevel(level); + pImpl->logger->set_level(static_cast(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); + } +} + diff --git a/Vivid2DRenderer/libs/logger/src/StringProcess.cpp b/Vivid2DRenderer/libs/logger/src/StringProcess.cpp new file mode 100644 index 0000000..1dea2d5 --- /dev/null +++ b/Vivid2DRenderer/libs/logger/src/StringProcess.cpp @@ -0,0 +1,118 @@ +#include "StringProcess.h" +#include +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"); +} + diff --git a/Vivid2DRenderer/libs/logger/src/StringProcess.h b/Vivid2DRenderer/libs/logger/src/StringProcess.h new file mode 100644 index 0000000..8526b0b --- /dev/null +++ b/Vivid2DRenderer/libs/logger/src/StringProcess.h @@ -0,0 +1,131 @@ +#pragma once +#include +#include + +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 +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"); +} diff --git a/Vivid2DRenderer/systems/RenderSystem.h b/Vivid2DRenderer/systems/RenderSystem.h index 0af9e80..21ce857 100644 --- a/Vivid2DRenderer/systems/RenderSystem.h +++ b/Vivid2DRenderer/systems/RenderSystem.h @@ -18,191 +18,191 @@ namespace Vivid2D::Render::Texture class Texture; } -// ǰ spdlog::logger Աͷļа +// 向前声明 spdlog::logger 以避免在头文件中包含其完整定义 namespace spdlog { class logger; } /** * @class RenderSystem - * @brief ṩһ̰߳ȫġе OpenGL API װ㡣 + * @brief 提供一个线程安全的、基于命令队列的 OpenGL API 封装层。 * @details - * һȫּ̬࣬ڽκ̵߳ȾŶӣһרõȾִ߳ǡ - * ȷ OpenGL ̰߳ȫԡṩ˶ OpenGL ״̬ɫ - * ߼ܣԼһڵԵĴơ - * ʹ÷̻߳߼߳еùľ̬ RenderSystem::drawElements - * ЩὫȾ¼СȾ̵߳ѭУ RenderSystem::replayQueue() - * ִŶӵ + * 这是一个完全静态的类,旨在将来自任何线程的渲染调用排队,并在一个专用的渲染线程上执行它们。 + * 这样做可以确保所有 OpenGL 操作的线程安全性。它还提供了对 OpenGL 状态、着色器、缓冲区和纹理的 + * 高级管理功能,以及一个用于调试的错误检查机制。 + * 使用方法:在主线程或其他逻辑线程中调用公开的静态方法(如 RenderSystem::drawElements), + * 这些方法会将渲染命令记录到队列中。在渲染线程的循环中,调用 RenderSystem::replayQueue() + * 来执行所有排队的命令。 */ class VIVID_2D_MYDLL_API RenderSystem { public: - // RenderSystem һ̬࣬˽ֹʵ + // RenderSystem 是一个静态工具类,因此禁止实例化。 RenderSystem() = delete; ~RenderSystem() = delete; RenderSystem(const RenderSystem&) = delete; RenderSystem& operator=(const RenderSystem&) = delete; using GLADloader = void* (*)(const char* name); - // ================== ־ϵͳ ================== + // ================== 日志系统管理 ================== /** - * @brief ʼ־ϵͳκ־֮ǰʼʱá + * @brief 初始化日志系统。必须在任何日志调用之前,在主函数开始时调用。 */ static void InitializeLogging(); /** - * @brief ر־ϵͳӦʱȷ־ˢ¡ + * @brief 关闭日志系统。应在主函数结束时调用以确保所有日志都被刷新。 */ static void ShutdownLogging(); - // ================== ʼ̹߳ ================== + // ================== 初始化与线程管理 ================== /** - * @brief ʼרõȾ̡߳ + * @brief 初始化并启动专用的渲染线程。 */ static void initRenderThread(); /** - * @brief ʼȾϵͳijʼ׶Ρڴ˽׶Σÿֱڵִ߳С + * @brief 开始渲染系统的初始化阶段。在此阶段,调用可以直接在调用线程上执行。 */ static void beginInitialization(); /** - * @brief Ⱦϵͳijʼ׶Ρ˺еöŶӡ + * @brief 结束渲染系统的初始化阶段。此后,所有调用都将被排队。 */ static void finishInitialization(); /** - * @brief 鵱ǰ߳ǷȾ̡߳ - * @return Ⱦ̣߳򷵻 true + * @brief 检查当前线程是否是渲染线程。 + * @return 如果是渲染线程,则返回 true。 */ static bool isOnRenderThread(); /** - * @brief 鵱ǰǷڳʼ׶Ρ - * @return dzʼ׶Σ򷵻 true + * @brief 检查当前是否处于初始化阶段。 + * @return 如果是初始化阶段,则返回 true。 */ static bool isInInitPhase(); /** - * @brief Եǰ̱߳Ⱦֹ̣߳ + * @brief 断言当前线程必须是渲染线程,否则程序将中止。 */ static void assertOnRenderThread(); /** - * @brief Եǰ̱߳Ⱦ̻߳ڳʼ׶Ρ + * @brief 断言当前线程必须是渲染线程或处于初始化阶段。 */ static void assertOnRenderThreadOrInit(); /** - * @brief ʹ GLAD OpenGL ָ롣 - * @param loader һָ룬ڻȡ OpenGL ĵַ glfwGetProcAddress + * @brief 使用 GLAD 加载 OpenGL 函数指针。 + * @param loader 一个函数指针,用于获取 OpenGL 函数的地址(例如 glfwGetProcAddress)。 */ static void loadGLFunctions(GLADloader loader); - // ================== Ⱦ ================== + // ================== 渲染命令队列 ================== /** - * @brief һȾãΪ lambda ¼УԱԺȾִ߳С - * @param renderCall ҪִеȾ + * @brief 将一个渲染调用(作为 lambda 函数)记录到命令队列中,以便稍后在渲染线程上执行。 + * @param renderCall 要执行的渲染操作。 */ static void recordRenderCall(std::function&& renderCall); /** - * @brief Ⱦִ߳едȾá + * @brief 在渲染线程上执行命令队列中的所有待处理渲染调用。 */ static void replayQueue(); - // ================== OpenGL ״̬װ ================== + // ================== OpenGL 状态管理封装 ================== /** - * @brief һ OpenGL ܣ GL_BLEND - * @param capability Ҫõ OpenGL ö١ + * @brief 启用一个 OpenGL 功能(例如 GL_BLEND)。 + * @param capability 要启用的 OpenGL 功能枚举。 */ static void enable(GLenum capability); /** - * @brief һ OpenGL ܡ - * @param capability Ҫõ OpenGL ö١ + * @brief 禁用一个 OpenGL 功能。 + * @param capability 要禁用的 OpenGL 功能枚举。 */ static void disable(GLenum capability); /** - * @brief ǰȾ״̬ɫϡӿڵȣ״̬ջ + * @brief 将当前的渲染状态(如着色器、混合、视口等)推入状态堆栈。 */ static void pushState(); /** - * @brief ״̬ջеָһȾ״̬ + * @brief 从状态堆栈中弹出并恢复上一个渲染状态。 */ static void popState(); /** - * @brief ȡǰ״̬ջĴС - * @return ջе״̬ + * @brief 获取当前状态堆栈的大小。 + * @return 堆栈中的状态数量。 */ static size_t getStateStackSize(); /** - * @brief ɫ + * @brief 设置清屏颜色。 */ static void clearColor(float r, float g, float b, float a); /** - * @brief ָĻ GL_COLOR_BUFFER_BIT - * @param mask ҪĻλ롣 + * @brief 清除指定的缓冲区(例如 GL_COLOR_BUFFER_BIT)。 + * @param mask 要清除的缓冲区的位域掩码。 */ static void clear(GLbitfield mask); /** - * @brief OpenGL ӿڡ + * @brief 设置 OpenGL 视口。 */ static void viewport(int x, int y, int width, int height); - // ================== VAO / VBO / EBO ================== + // ================== VAO / VBO / EBO 操作 ================== /** - * @brief һ (VAO) - * @return ´ VAO ľ + * @brief 生成一个顶点数组对象 (VAO)。 + * @return 新创建的 VAO 的句柄。 */ static GLuint GenVertexArrays(); /** - * @brief ɾһ VAO - * @param vao Ҫɾ VAO ľ + * @brief 删除一个 VAO。 + * @param vao 要删除的 VAO 的句柄。 */ static void DeleteVertexArrays(GLuint vao); /** - * @brief һ VAO - * @param vao Ҫ󶨵 VAO ľ + * @brief 绑定一个 VAO。 + * @param vao 要绑定的 VAO 的句柄。 */ static void BindVertexArray(GLuint vao); /** - * @brief һ (VBO/EBO) - * @return ´Ļľ + * @brief 生成一个缓冲区对象 (VBO/EBO)。 + * @return 新创建的缓冲区的句柄。 */ static GLuint GenBuffers(); /** - * @brief ɾһ - * @param buffer ҪɾĻľ + * @brief 删除一个缓冲区对象。 + * @param buffer 要删除的缓冲区的句柄。 */ static void DeleteBuffers(GLuint buffer); /** - * @brief һ - * @param target Ŀ ( GL_ARRAY_BUFFER) - * @param buffer Ҫ󶨵Ļľ + * @brief 绑定一个缓冲区对象。 + * @param target 缓冲区的目标 (例如 GL_ARRAY_BUFFER)。 + * @param buffer 要绑定的缓冲区的句柄。 */ static void BindBuffer(GLenum target, GLuint buffer); /** - * @brief ϴǰ󶨵Ļ - * @param target Ŀꡣ - * @param size ݵĴСֽΪλ - * @param data ָݵָ롣 - * @param usage ݵԤ; ( GL_STATIC_DRAW) + * @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 ================== + // ================== 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 ȡɫ uniform λá - * @param program ɫľ - * @param name uniform ơ - * @return uniform λá + * @brief 获取着色器程序中 uniform 变量的位置。 + * @param program 着色器程序的句柄。 + * @param name uniform 变量的名称。 + * @return uniform 变量的位置。 */ static GLint getUniformLocation(GLuint program, const std::string& name); - // ================== ================== + // ================== 绘制命令 ================== /** - * @brief ߿ + * @brief 设置线宽。 */ static void lineWidth(float width); /** - * @brief ʹлơ + * @brief 使用索引进行绘制。 */ static void drawElements(GLenum mode, GLsizei count, GLenum type, const void* indices); /** - * @brief ֱʹöлơ + * @brief 直接使用顶点数组进行绘制。 */ static void drawArrays(GLenum mode, GLint first, GLsizei count); - // ================== ģʽ ================== + // ================== 混合模式 ================== /** - * @brief ûϡ + * @brief 启用混合。 */ static void enableBlend(); /** - * @brief ûϡ + * @brief 禁用混合。 */ static void disableBlend(); /** - * @brief ûϺ + * @brief 设置混合函数。 */ static void blendFunc(GLenum sfactor, GLenum dfactor); /** - * @brief Ĭϵ Alpha Ϻ (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) + * @brief 设置默认的 Alpha 混合函数 (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)。 */ static void defaultBlendFunc(); - // ================== ɫ ================== + // ================== 着色器程序管理 ================== /** - * @brief һյɫ - * @return ³ľ + * @brief 创建一个空的着色器程序。 + * @return 新程序的句柄。 */ static GLuint createProgram(); /** - * @brief ȡǰ󶨵ɫ - * @return ǰľ + * @brief 获取当前绑定的着色器程序。 + * @return 当前程序的句柄。 */ static GLint getCurrentProgram(); /** - * @brief һɫӵɫ + * @brief 将一个着色器附加到着色器程序。 */ static void attachShader(GLuint program, GLuint shader); /** - * @brief һɫ + * @brief 链接一个着色器程序。 */ static void linkProgram(GLuint program); /** - * @brief ȡɫIJ + * @brief 获取着色器程序的参数。 */ static GLint getProgrami(GLuint program, GLenum pname); /** - * @brief ȡɫ־Ϣ + * @brief 获取着色器程序的日志信息。 */ static std::string getProgramInfoLog(GLuint program); /** - * @brief ӳзһɫ + * @brief 从程序中分离一个着色器。 */ static void detachShader(GLuint program, GLuint shader); /** - * @brief ɾһɫ + * @brief 删除一个着色器程序。 */ static void deleteProgram(GLuint program); /** - * @brief ӶƬɫԴһij + * @brief 链接顶点和片段着色器以创建一个完整的程序。 */ static GLuint linkProgram(GLuint vertexShader, GLuint fragmentShader); /** - * @brief Ӷ㡢κƬɫԴһij + * @brief 链接顶点、几何和片段着色器以创建一个完整的程序。 */ static GLuint linkProgram(GLuint vertexShader, GLuint geometryShader, GLuint fragmentShader); /** - * @brief һɫ + * @brief 激活一个着色器程序。 */ static void useProgram(GLuint program); - // ================== ɫ ================== + // ================== 着色器管理 ================== /** - * @brief һָ͵ɫ - * @param type ɫ ( GL_VERTEX_SHADER) - * @return ɫľ + * @brief 创建一个指定类型的着色器对象。 + * @param type 着色器类型 (例如 GL_VERTEX_SHADER)。 + * @return 新着色器对象的句柄。 */ static GLuint createShader(GLenum type); /** - * @brief ΪɫԴ롣 + * @brief 为着色器设置源代码。 */ static void shaderSource(GLuint shader, const std::string& source); /** - * @brief һɫ + * @brief 编译一个着色器。 */ static void compileShader(GLuint shader); /** - * @brief ȡɫIJ + * @brief 获取着色器的参数。 */ static GLint getShaderi(GLuint shader, GLenum pname); /** - * @brief ȡɫ־Ϣ + * @brief 获取着色器的日志信息。 */ static std::string getShaderInfoLog(GLuint shader); /** - * @brief ɾһɫ + * @brief 删除一个着色器。 */ static void deleteShader(GLuint shader); /** - * @brief Դһָ͵ɫ - * @return ɫ + * @brief 从源代码编译一个指定类型的着色器。 + * @return 编译后的着色器句柄。 */ static GLuint compileShader(GLenum type, const std::string& source); - // ================== Ȳ ================== + // ================== 深度测试 ================== static void depthFunc(GLenum func); static void depthMask(bool flag); static void clearDepth(double depth); static void enableDepthTest(); static void disableDepthTest(); - // ================== ================== + // ================== 纹理管理 ================== /** - * @brief һ 2D ǰԪ - * @param texture Ҫ󶨵ľ + * @brief 绑定一个 2D 纹理到当前活动的纹理单元。 + * @param texture 要绑定的纹理的句柄。 */ static void bindTexture(GLuint texture); /** - * @brief һ Texture ָԪ - * @details һԪͰϲΪһ - * ȫύȾ̡߳ - * @param texture Ҫ󶨵 Texture ijá - * @param textureUnit Ҫ󶨵Ԫ (0, 1, 2, ...) + * @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 һԪ - * @param texture ҪԪ ( GL_TEXTURE0) + * @brief 激活一个纹理单元。 + * @param texture 要激活的纹理单元 (例如 GL_TEXTURE0)。 */ static void activeTexture(GLenum texture); /** - * @brief һ - * @return ľ + * @brief 生成一个纹理对象。 + * @return 新纹理的句柄。 */ static GLuint genTextures(); /** - * @brief ɾһ - * @param texture Ҫɾľ + * @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 һĬϵ 1x1 ɫ - * @return Ĭľ + * @brief 创建一个默认的 1x1 白色纹理。 + * @return 默认纹理的句柄。 */ static GLuint createDefaultTexture(); - // ================== ================== + // ================== 顶点属性 ================== 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); - // ================== ߷ ================== + // ================== 工具方法 ================== static void readPixels(int x, int y, int width, int height, GLenum format, GLenum type, void* pixels); /** - * @brief Ƿ֧ij OpenGL չ + * @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 ¼ϸ OpenGL Ϣ + * @brief 记录详细的 OpenGL 和驱动信息。 */ static void logDetailedGLInfo(); /** - * @brief һĬϵ OpenGL ״̬ûϣɫ + * @brief 设置一套默认的 OpenGL 状态(例如启用混合,设置清屏色)。 */ static void setupDefaultState(); /** - * @brief 鲢¼κη OpenGL - * @param operation ¼IJơ + * @brief 检查并记录任何发生的 OpenGL 错误。 + * @param operation 导致检查的操作的描述性名称。 */ static void checkGLError(const std::string& operation); - // ================== ȡ״̬ ================== + // ================== 获取状态 ================== static int getViewportWidth(); static int getViewportHeight(); static glm::vec4 getClearColor(); /** - * @brief ȡǰȾе - * @return дС + * @brief 获取当前渲染命令队列中的命令数量。 + * @return 队列大小。 */ static size_t getQueueSize(); private: struct RenderState; - // ˽еġֱִGLõİ汾 + // 私有的、直接执行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); - // ̬Ա + // 静态成员变量 static std::thread::id s_RenderThreadId; static std::atomic s_IsInInit; static std::queue> s_RenderQueue; static std::mutex s_RenderQueueMutex; static std::atomic s_IsReplayingQueue; - // ================== RenderState ṹʵ ================== - struct RenderSystem::RenderState { + // ================== RenderState 结构体和实现 ================== + struct RenderState { GLint currentProgram = 0; GLboolean blendEnabled = GL_FALSE; GLboolean depthTestEnabled = GL_FALSE; diff --git a/Vivid2DRenderer/systems/defs.h b/Vivid2DRenderer/systems/defs.h new file mode 100644 index 0000000..940cd46 --- /dev/null +++ b/Vivid2DRenderer/systems/defs.h @@ -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 \ No newline at end of file diff --git a/Vivid2DRenderer/vcpkg.json b/Vivid2DRenderer/vcpkg.json index 4de7ac8..f17f7f6 100644 --- a/Vivid2DRenderer/vcpkg.json +++ b/Vivid2DRenderer/vcpkg.json @@ -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" } \ No newline at end of file