Extra2D/Easy2D/src/graphics/shader_system.cpp

484 lines
12 KiB
C++
Raw Normal View History

#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