484 lines
12 KiB
C++
484 lines
12 KiB
C++
#include <easy2d/graphics/shader_system.h>
|
||
#include <easy2d/core/color.h>
|
||
#include <easy2d/utils/logger.h>
|
||
#include <fstream>
|
||
#include <sstream>
|
||
#include <sys/stat.h>
|
||
|
||
#ifdef _WIN32
|
||
#include <windows.h>
|
||
#endif
|
||
|
||
namespace easy2d {
|
||
|
||
// ============================================================================
|
||
// 内置Shader源码
|
||
// ============================================================================
|
||
|
||
// 标准精灵着色器 (GLES 3.2)
|
||
static const char* BUILTIN_SPRITE_VERT = R"(
|
||
#version 300 es
|
||
precision highp float;
|
||
layout(location = 0) in vec2 a_position;
|
||
layout(location = 1) in vec2 a_texCoord;
|
||
layout(location = 2) in vec4 a_color;
|
||
|
||
uniform mat4 u_viewProjection;
|
||
uniform mat4 u_model;
|
||
|
||
out vec2 v_texCoord;
|
||
out vec4 v_color;
|
||
|
||
void main() {
|
||
gl_Position = u_viewProjection * u_model * vec4(a_position, 0.0, 1.0);
|
||
v_texCoord = a_texCoord;
|
||
v_color = a_color;
|
||
}
|
||
)";
|
||
|
||
static const char* BUILTIN_SPRITE_FRAG = R"(
|
||
#version 300 es
|
||
precision highp float;
|
||
in vec2 v_texCoord;
|
||
in vec4 v_color;
|
||
|
||
uniform sampler2D u_texture;
|
||
uniform float u_opacity;
|
||
|
||
out vec4 fragColor;
|
||
|
||
void main() {
|
||
vec4 texColor = texture(u_texture, v_texCoord);
|
||
fragColor = texColor * v_color;
|
||
fragColor.a *= u_opacity;
|
||
|
||
if (fragColor.a < 0.01) {
|
||
discard;
|
||
}
|
||
}
|
||
)";
|
||
|
||
// 粒子着色器 (GLES 3.2)
|
||
static const char* BUILTIN_PARTICLE_VERT = R"(
|
||
#version 300 es
|
||
precision highp float;
|
||
layout(location = 0) in vec2 a_position;
|
||
layout(location = 1) in vec2 a_texCoord;
|
||
layout(location = 2) in vec4 a_color;
|
||
layout(location = 3) in float a_size;
|
||
layout(location = 4) in float a_rotation;
|
||
|
||
uniform mat4 u_viewProjection;
|
||
|
||
out vec2 v_texCoord;
|
||
out vec4 v_color;
|
||
|
||
void main() {
|
||
float c = cos(a_rotation);
|
||
float s = sin(a_rotation);
|
||
mat2 rot = mat2(c, -s, s, c);
|
||
|
||
vec2 pos = rot * a_position * a_size;
|
||
gl_Position = u_viewProjection * vec4(pos, 0.0, 1.0);
|
||
|
||
v_texCoord = a_texCoord;
|
||
v_color = a_color;
|
||
}
|
||
)";
|
||
|
||
static const char* BUILTIN_PARTICLE_FRAG = R"(
|
||
#version 300 es
|
||
precision highp float;
|
||
in vec2 v_texCoord;
|
||
in vec4 v_color;
|
||
|
||
uniform sampler2D u_texture;
|
||
uniform int u_textureEnabled;
|
||
|
||
out vec4 fragColor;
|
||
|
||
void main() {
|
||
vec4 color = v_color;
|
||
|
||
if (u_textureEnabled > 0) {
|
||
color *= texture(u_texture, v_texCoord);
|
||
}
|
||
|
||
// 圆形粒子
|
||
vec2 center = v_texCoord - vec2(0.5);
|
||
float dist = length(center);
|
||
float alpha = 1.0 - smoothstep(0.4, 0.5, dist);
|
||
color.a *= alpha;
|
||
|
||
if (color.a < 0.01) {
|
||
discard;
|
||
}
|
||
|
||
fragColor = color;
|
||
}
|
||
)";
|
||
|
||
// 后处理着色器 (GLES 3.2)
|
||
static const char* BUILTIN_POSTPROCESS_VERT = R"(
|
||
#version 300 es
|
||
precision highp float;
|
||
layout(location = 0) in vec2 a_position;
|
||
layout(location = 1) in vec2 a_texCoord;
|
||
|
||
out vec2 v_texCoord;
|
||
|
||
void main() {
|
||
gl_Position = vec4(a_position, 0.0, 1.0);
|
||
v_texCoord = a_texCoord;
|
||
}
|
||
)";
|
||
|
||
static const char* BUILTIN_POSTPROCESS_FRAG = R"(
|
||
#version 300 es
|
||
precision highp float;
|
||
in vec2 v_texCoord;
|
||
|
||
uniform sampler2D u_texture;
|
||
uniform vec2 u_resolution;
|
||
uniform float u_time;
|
||
|
||
out vec4 fragColor;
|
||
|
||
void main() {
|
||
fragColor = texture(u_texture, v_texCoord);
|
||
}
|
||
)";
|
||
|
||
// 形状渲染着色器 (GLES 3.2)
|
||
static const char* BUILTIN_SHAPE_VERT = R"(
|
||
#version 300 es
|
||
precision highp float;
|
||
layout(location = 0) in vec2 a_position;
|
||
layout(location = 1) in vec4 a_color;
|
||
|
||
uniform mat4 u_viewProjection;
|
||
|
||
out vec4 v_color;
|
||
|
||
void main() {
|
||
gl_Position = u_viewProjection * vec4(a_position, 0.0, 1.0);
|
||
v_color = a_color;
|
||
}
|
||
)";
|
||
|
||
static const char* BUILTIN_SHAPE_FRAG = R"(
|
||
#version 300 es
|
||
precision highp float;
|
||
in vec4 v_color;
|
||
|
||
out vec4 fragColor;
|
||
|
||
void main() {
|
||
fragColor = v_color;
|
||
}
|
||
)";
|
||
|
||
// ============================================================================
|
||
// ShaderSystem实现
|
||
// ============================================================================
|
||
|
||
ShaderSystem& ShaderSystem::getInstance() {
|
||
static ShaderSystem instance;
|
||
return instance;
|
||
}
|
||
|
||
bool ShaderSystem::init() {
|
||
E2D_INFO("初始化Shader系统...");
|
||
|
||
if (!loadBuiltinShaders()) {
|
||
E2D_ERROR("加载内置Shader失败!");
|
||
return false;
|
||
}
|
||
|
||
E2D_INFO("Shader系统初始化完成");
|
||
return true;
|
||
}
|
||
|
||
void ShaderSystem::shutdown() {
|
||
E2D_INFO("关闭Shader系统...");
|
||
clear();
|
||
|
||
builtinSpriteShader_.reset();
|
||
builtinParticleShader_.reset();
|
||
builtinPostProcessShader_.reset();
|
||
builtinShapeShader_.reset();
|
||
}
|
||
|
||
bool ShaderSystem::loadBuiltinShaders() {
|
||
// 加载精灵Shader
|
||
builtinSpriteShader_ = std::make_shared<GLShader>();
|
||
if (!builtinSpriteShader_->compileFromSource(BUILTIN_SPRITE_VERT, BUILTIN_SPRITE_FRAG)) {
|
||
E2D_ERROR("编译内置精灵Shader失败!");
|
||
return false;
|
||
}
|
||
|
||
// 加载粒子Shader
|
||
builtinParticleShader_ = std::make_shared<GLShader>();
|
||
if (!builtinParticleShader_->compileFromSource(BUILTIN_PARTICLE_VERT, BUILTIN_PARTICLE_FRAG)) {
|
||
E2D_ERROR("编译内置粒子Shader失败!");
|
||
return false;
|
||
}
|
||
|
||
// 加载后处理Shader
|
||
builtinPostProcessShader_ = std::make_shared<GLShader>();
|
||
if (!builtinPostProcessShader_->compileFromSource(BUILTIN_POSTPROCESS_VERT, BUILTIN_POSTPROCESS_FRAG)) {
|
||
E2D_ERROR("编译内置后处理Shader失败!");
|
||
return false;
|
||
}
|
||
|
||
// 加载形状Shader
|
||
builtinShapeShader_ = std::make_shared<GLShader>();
|
||
if (!builtinShapeShader_->compileFromSource(BUILTIN_SHAPE_VERT, BUILTIN_SHAPE_FRAG)) {
|
||
E2D_ERROR("编译内置形状Shader失败!");
|
||
return false;
|
||
}
|
||
|
||
E2D_INFO("内置Shader加载成功");
|
||
return true;
|
||
}
|
||
|
||
Ptr<GLShader> ShaderSystem::loadFromFile(const std::string& name,
|
||
const std::string& vertPath,
|
||
const std::string& fragPath) {
|
||
// 读取文件内容
|
||
std::string vertSource = readFile(vertPath);
|
||
std::string fragSource = readFile(fragPath);
|
||
|
||
if (vertSource.empty()) {
|
||
E2D_ERROR("无法读取顶点着色器文件: {}", vertPath);
|
||
return nullptr;
|
||
}
|
||
|
||
if (fragSource.empty()) {
|
||
E2D_ERROR("无法读取片段着色器文件: {}", fragPath);
|
||
return nullptr;
|
||
}
|
||
|
||
// 编译Shader
|
||
auto shader = std::make_shared<GLShader>();
|
||
if (!shader->compileFromSource(vertSource.c_str(), fragSource.c_str())) {
|
||
E2D_ERROR("编译Shader '{}' 失败", name);
|
||
return nullptr;
|
||
}
|
||
|
||
// 存储Shader信息
|
||
ShaderInfo info;
|
||
info.shader = shader;
|
||
info.vertPath = vertPath;
|
||
info.fragPath = fragPath;
|
||
info.vertModifiedTime = getFileModifiedTime(vertPath);
|
||
info.fragModifiedTime = getFileModifiedTime(fragPath);
|
||
info.isBuiltin = false;
|
||
|
||
shaders_[name] = std::move(info);
|
||
|
||
E2D_INFO("加载Shader '{}' 成功", name);
|
||
return shader;
|
||
}
|
||
|
||
Ptr<GLShader> ShaderSystem::loadFromSource(const std::string& name,
|
||
const std::string& vertSource,
|
||
const std::string& fragSource) {
|
||
auto shader = std::make_shared<GLShader>();
|
||
if (!shader->compileFromSource(vertSource.c_str(), fragSource.c_str())) {
|
||
E2D_ERROR("编译Shader '{}' 失败", name);
|
||
return nullptr;
|
||
}
|
||
|
||
ShaderInfo info;
|
||
info.shader = shader;
|
||
info.vertModifiedTime = 0;
|
||
info.fragModifiedTime = 0;
|
||
info.isBuiltin = false;
|
||
|
||
shaders_[name] = std::move(info);
|
||
|
||
E2D_INFO("加载Shader '{}' 成功", name);
|
||
return shader;
|
||
}
|
||
|
||
Ptr<GLShader> ShaderSystem::get(const std::string& name) {
|
||
auto it = shaders_.find(name);
|
||
if (it != shaders_.end()) {
|
||
return it->second.shader;
|
||
}
|
||
return nullptr;
|
||
}
|
||
|
||
bool ShaderSystem::has(const std::string& name) const {
|
||
return shaders_.find(name) != shaders_.end();
|
||
}
|
||
|
||
void ShaderSystem::remove(const std::string& name) {
|
||
shaders_.erase(name);
|
||
}
|
||
|
||
void ShaderSystem::clear() {
|
||
shaders_.clear();
|
||
}
|
||
|
||
void ShaderSystem::setFileWatching(bool enable) {
|
||
fileWatching_ = enable;
|
||
if (enable) {
|
||
E2D_INFO("启用Shader文件监视");
|
||
} else {
|
||
E2D_INFO("禁用Shader文件监视");
|
||
}
|
||
}
|
||
|
||
void ShaderSystem::updateFileWatching() {
|
||
if (!fileWatching_) return;
|
||
|
||
watchTimer_ += 0.016f; // 假设60fps
|
||
if (watchTimer_ >= WATCH_INTERVAL) {
|
||
watchTimer_ = 0.0f;
|
||
checkAndReload();
|
||
}
|
||
}
|
||
|
||
void ShaderSystem::checkAndReload() {
|
||
for (auto& [name, info] : shaders_) {
|
||
if (info.isBuiltin) continue;
|
||
if (info.vertPath.empty() || info.fragPath.empty()) continue;
|
||
|
||
uint64_t vertTime = getFileModifiedTime(info.vertPath);
|
||
uint64_t fragTime = getFileModifiedTime(info.fragPath);
|
||
|
||
if (vertTime > info.vertModifiedTime || fragTime > info.fragModifiedTime) {
|
||
E2D_INFO("检测到Shader '{}' 文件变化,正在重载...", name);
|
||
reload(name);
|
||
}
|
||
}
|
||
}
|
||
|
||
bool ShaderSystem::reload(const std::string& name) {
|
||
auto it = shaders_.find(name);
|
||
if (it == shaders_.end()) {
|
||
E2D_ERROR("无法重载不存在的Shader '{}'", name);
|
||
return false;
|
||
}
|
||
|
||
auto& info = it->second;
|
||
if (info.isBuiltin) {
|
||
E2D_WARN("无法重载内置Shader '{}'", name);
|
||
return false;
|
||
}
|
||
|
||
if (info.vertPath.empty() || info.fragPath.empty()) {
|
||
E2D_ERROR("Shader '{}' 没有关联的文件路径", name);
|
||
return false;
|
||
}
|
||
|
||
// 重新加载
|
||
auto newShader = loadFromFile(name, info.vertPath, info.fragPath);
|
||
if (newShader) {
|
||
E2D_INFO("重载Shader '{}' 成功", name);
|
||
return true;
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
void ShaderSystem::reloadAll() {
|
||
for (const auto& [name, info] : shaders_) {
|
||
if (!info.isBuiltin) {
|
||
reload(name);
|
||
}
|
||
}
|
||
}
|
||
|
||
Ptr<GLShader> ShaderSystem::getBuiltinSpriteShader() {
|
||
return builtinSpriteShader_;
|
||
}
|
||
|
||
Ptr<GLShader> ShaderSystem::getBuiltinParticleShader() {
|
||
return builtinParticleShader_;
|
||
}
|
||
|
||
Ptr<GLShader> ShaderSystem::getBuiltinPostProcessShader() {
|
||
return builtinPostProcessShader_;
|
||
}
|
||
|
||
Ptr<GLShader> ShaderSystem::getBuiltinShapeShader() {
|
||
return builtinShapeShader_;
|
||
}
|
||
|
||
std::string ShaderSystem::readFile(const std::string& filepath) {
|
||
std::ifstream file(filepath, std::ios::in | std::ios::binary);
|
||
if (!file.is_open()) {
|
||
return "";
|
||
}
|
||
|
||
std::stringstream buffer;
|
||
buffer << file.rdbuf();
|
||
return buffer.str();
|
||
}
|
||
|
||
uint64_t ShaderSystem::getFileModifiedTime(const std::string& filepath) {
|
||
#ifdef _WIN32
|
||
struct _stat64 statBuf;
|
||
if (_stat64(filepath.c_str(), &statBuf) == 0) {
|
||
return static_cast<uint64_t>(statBuf.st_mtime);
|
||
}
|
||
#else
|
||
struct stat statBuf;
|
||
if (stat(filepath.c_str(), &statBuf) == 0) {
|
||
return static_cast<uint64_t>(statBuf.st_mtime);
|
||
}
|
||
#endif
|
||
return 0;
|
||
}
|
||
|
||
// ============================================================================
|
||
// ShaderParams实现
|
||
// ============================================================================
|
||
|
||
ShaderParams::ShaderParams(GLShader& shader) : shader_(shader) {}
|
||
|
||
ShaderParams& ShaderParams::setBool(const std::string& name, bool value) {
|
||
shader_.setBool(name, value);
|
||
return *this;
|
||
}
|
||
|
||
ShaderParams& ShaderParams::setInt(const std::string& name, int value) {
|
||
shader_.setInt(name, value);
|
||
return *this;
|
||
}
|
||
|
||
ShaderParams& ShaderParams::setFloat(const std::string& name, float value) {
|
||
shader_.setFloat(name, value);
|
||
return *this;
|
||
}
|
||
|
||
ShaderParams& ShaderParams::setVec2(const std::string& name, const glm::vec2& value) {
|
||
shader_.setVec2(name, value);
|
||
return *this;
|
||
}
|
||
|
||
ShaderParams& ShaderParams::setVec3(const std::string& name, const glm::vec3& value) {
|
||
shader_.setVec3(name, value);
|
||
return *this;
|
||
}
|
||
|
||
ShaderParams& ShaderParams::setVec4(const std::string& name, const glm::vec4& value) {
|
||
shader_.setVec4(name, value);
|
||
return *this;
|
||
}
|
||
|
||
ShaderParams& ShaderParams::setMat4(const std::string& name, const glm::mat4& value) {
|
||
shader_.setMat4(name, value);
|
||
return *this;
|
||
}
|
||
|
||
ShaderParams& ShaderParams::setColor(const std::string& name, const Color& color) {
|
||
shader_.setVec4(name, glm::vec4(color.r, color.g, color.b, color.a));
|
||
return *this;
|
||
}
|
||
|
||
} // namespace easy2d
|