我正在编写一个 OpenGL C++ 包装器。该包装器旨在减少复杂且易出错的用法。
例如,我目前希望用户只关注一点点 OpenGL Context
。为此,我编写了一个类 gl_texture_2d
。众所周知,一个OpenGL纹理
基本上有以下操作:
- 设置u/v参数为
repeat
/mirror
等 - 将
min
/mag
filter
设置为linear
- ...
基于此,我们有:
class gl_texture_2d
{
public:
void mirror_u(); // set u parameter as mirror model
void mirror_v(); // set v parameter as mirror model
void linear_min_filter(); // ...
void linear_mag_filter(); // ...
};
好吧,我们知道,只有当 OpenGL 纹理对象的句柄
当前绑定(bind)到 OpenGL 上下文
时,我们才能执行这些操作。
假设我们有一个函数这样做:
无效绑定(bind)(GLuint htex);//实际上是相关 GL 函数的别名
好的,我们现在可以将我们的 gl_texture_2d
用法设计为:
gl_texture_2d tex;
bind(tex.handle());
tex.mirror_u();
tex.linear_min_filter();
unbind(tex.handle());
它证实了 GL 的逻辑,但它失去了 wrapper 的意义,对吧?作为用户,我希望这样操作:
gl_texture_2d tex;
tex.mirror_u();
tex.linear_min_filter();
要实现这一点,我们必须实现类似以下功能:
void gl_texture_2d::mirror_u()
{
glBindTexture(GL_TEXTURE_2D, handle());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
glBindTexture(GL_TEXTURE_2D, 0);
}
始终在内部进行绑定(bind)操作可确保操作有效。但成本昂贵!
代码:
tex.mirror_u();
tex.mirror_v();
会展开成一对无意义的绑定(bind)/解绑操作。
那么有没有什么机制可以让编译器知道:
- 如果
bind(b)
紧跟在bind(a)
之后,则可以删除bind(a)
; - 如果
bind(a)
在一个 block 中出现两次,最后一次无效。
最佳答案
如果您正在使用 pre-DSA OpenGL ,并且您绝对必须使用您自己的 API 直接包装 OpenGL 调用,然后用户可能必须了解整个绑定(bind)到编辑的事情。毕竟,如果他们出于渲染目的绑定(bind)了一个纹理,然后他们尝试修改一个纹理,这可能会损坏当前的绑定(bind)。
因此,您应该将绑定(bind)到编辑的概念直接构建到 API 中。
也就是说,纹理对象(顺便说一句,它应该不仅限于二维纹理)实际上不应该有修改它的函数,因为你不能在不绑定(bind)它的情况下修改 OpenGL 纹理(或者没有你真正应该学习的 DSA)。它不应该有 mirror_u
等等;这些函数应该是 Binder 对象的一部分:
bound_texture bind(some_texture, tex_unit);
bind.mirror_u();
...
bound_texture
的构造函数将 some_texture
绑定(bind)到 tex_unit
。它的成员函数将修改该纹理(注意:它们需要调用 glActiveTexture
以确保没有人更改事件纹理单元)。
bound_texture
的析构函数应该自动解除绑定(bind)纹理。但是你应该有一个 release
成员函数来手动解除绑定(bind)。
关于c++ - 如何让C++编译器知道一个函数是 `Idempotent`,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41287151/