117 lines
2.7 KiB
C++
117 lines
2.7 KiB
C++
#include <renderer/rhi/opengl/gl_pipeline.h>
|
||
#include <renderer/rhi/opengl/gl_utils.h>
|
||
|
||
namespace extra2d {
|
||
|
||
GLPipeline::GLPipeline(const PipelineDesc &desc) : desc_(desc), vao_(0) {}
|
||
|
||
GLPipeline::~GLPipeline() { destroy(); }
|
||
|
||
bool GLPipeline::create() {
|
||
// 创建 VAO
|
||
glGenVertexArrays(1, &vao_);
|
||
if (vao_ == 0) {
|
||
return false;
|
||
}
|
||
|
||
glBindVertexArray(vao_);
|
||
|
||
// 配置顶点属性
|
||
const auto &layout = desc_.vertexLayout;
|
||
for (const auto &attr : layout.attributes) {
|
||
glEnableVertexAttribArray(attr.location);
|
||
|
||
GLenum type = GL_FLOAT;
|
||
GLint size = 1;
|
||
GLboolean normalized = GL_FALSE;
|
||
|
||
switch (attr.format) {
|
||
case VertexFormat::Float1:
|
||
size = 1;
|
||
break;
|
||
case VertexFormat::Float2:
|
||
size = 2;
|
||
break;
|
||
case VertexFormat::Float3:
|
||
size = 3;
|
||
break;
|
||
case VertexFormat::Float4:
|
||
size = 4;
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
|
||
glVertexAttribPointer(attr.location, size, type, normalized, layout.stride,
|
||
reinterpret_cast<const void *>(attr.offset));
|
||
}
|
||
|
||
glBindVertexArray(0);
|
||
return true;
|
||
}
|
||
|
||
void GLPipeline::destroy() {
|
||
if (vao_ != 0) {
|
||
glDeleteVertexArrays(1, &vao_);
|
||
vao_ = 0;
|
||
}
|
||
}
|
||
|
||
void GLPipeline::bind() {
|
||
// 绑定着色器程序
|
||
if (shaderProgram_ != 0) {
|
||
glUseProgram(shaderProgram_);
|
||
}
|
||
|
||
// 注意:VAO 需要与具体的顶点缓冲区绑定才能工作
|
||
// 所以我们不在此处绑定 VAO,而是在渲染时动态配置顶点属性
|
||
// 这样可以支持不同的 Mesh 使用相同的 Pipeline
|
||
|
||
// 应用混合状态
|
||
if (desc_.blendState.enabled) {
|
||
glEnable(GL_BLEND);
|
||
glBlendFunc(blendFactorToGL(desc_.blendState.srcFactor),
|
||
blendFactorToGL(desc_.blendState.dstFactor));
|
||
} else {
|
||
glDisable(GL_BLEND);
|
||
}
|
||
|
||
// 应用深度状态
|
||
if (desc_.depthStencilState.depthTestEnabled) {
|
||
glEnable(GL_DEPTH_TEST);
|
||
glDepthFunc(compareFuncToGL(desc_.depthStencilState.depthCompare));
|
||
glDepthMask(desc_.depthStencilState.depthWriteEnabled ? GL_TRUE : GL_FALSE);
|
||
} else {
|
||
glDisable(GL_DEPTH_TEST);
|
||
}
|
||
|
||
// 应用光栅化状态
|
||
if (desc_.rasterizerState.cullEnabled) {
|
||
glEnable(GL_CULL_FACE);
|
||
glCullFace(desc_.rasterizerState.cullFrontFace ? GL_FRONT : GL_BACK);
|
||
glFrontFace(desc_.rasterizerState.frontCCW ? GL_CCW : GL_CW);
|
||
} else {
|
||
glDisable(GL_CULL_FACE);
|
||
}
|
||
}
|
||
|
||
void GLPipeline::unbind() { glBindVertexArray(0); }
|
||
|
||
ShaderHandle GLPipeline::getVertexShader() const {
|
||
return desc_.vertexShader;
|
||
}
|
||
|
||
ShaderHandle GLPipeline::getFragmentShader() const {
|
||
return desc_.fragmentShader;
|
||
}
|
||
|
||
const VertexLayout& GLPipeline::getVertexLayout() const {
|
||
return desc_.vertexLayout;
|
||
}
|
||
|
||
bool GLPipeline::isValid() const {
|
||
return vao_ != 0;
|
||
}
|
||
|
||
} // namespace extra2d
|