在 C11 及更高版本
C++ 11 提供了增强 RAII 封装的 OpenGL 对象功能的工具。如果没有像移动语义这样的 C++ 11 特性,如果你想传递它们,就必须动态分配这些对象,因为它们无法被复制。移动支持允许它们像普通值一样来回传递,但不能通过复制:
class BufferObject
{
public:
BufferObject(GLenum target, GLsizeiptr size, const void *data, GLenum usage)
{
glGenBuffers(1, &object_);
glBindBuffer(target, object_);
glBufferData(target, size, data, usage);
glBindBuffer(target, 0);
}
//Cannot be copied.
BufferObject(const BufferObject &) = delete;
BufferObject &operator=(const BufferObject &) = delete;
//Can be moved
BufferObject(BufferObject &&other) noexcept : object_(other.Release())
{}
//Self-assignment is OK with this implementation.
BufferObject &operator=(BufferObject &&other) noexcept
{
Reset(other.Release());
}
//Destroys the old buffer and claims ownership of a new buffer object.
//It's OK to call glDeleteBuffers on buffer object 0.
GLuint Reset(GLuint object = 0)
{
glDeleteBuffers(1, &object_);
object_ = object;
}
//Relinquishes ownership of the object without destroying it
GLuint Release()
{
GLuint ret = object_;
object_ = 0;
return ret;
}
~BufferObject()
{
Reset();
}
//Accessors and manipulators
void Bind(GLenum target) const {glBindBuffer(target, object_);}
GLuint GetObject() const {return object_;}
private:
GLuint object_;
};
这样的类型可以通过函数返回:
BufferObject CreateStaticBuffer(GLsizeiptr byteSize) {return BufferObject(GL_ARRAY_BUFFER, byteSize, nullptr, GL_STATIC_DRAW);}
这允许你将它们存储在你自己的(隐式移动)类型中:
struct Mesh
{
public:
private:
//Default member initializer.
BufferObject buff_ = CreateStaticBuffer(someSize);
};
范围绑定器类也可以具有移动语义,从而允许从函数返回绑定器并将其存储在 C++标准库容器中:
class BindBuffer
{
public:
BindBuffer(GLenum target, const BufferObject &buff) : target_(target)
{
buff.Bind(target_);
}
//Non-copyable.
BindBuffer(const BindBuffer &) = delete;
BindBuffer &operator=(const BindBuffer &) = delete;
//Move-constructible.
BindBuffer(BindBuffer &&other) noexcept : target_(other.target_)
{
other.target_ = 0;
}
//Not move-assignable.
BindBuffer &operator=(BindBuffer &&) = delete;
~BindBuffer()
{
//Only unbind if not moved from.
if(target_)
glBindBuffer(target_, 0);
}
private:
GLenum target_;
};
请注意,对象是可构造的,但不能移动 - 可分配。这样做的想法是防止重新绑定范围的缓冲区绑定。一旦设置,唯一可以解除它的东西就是被移除。