Boolean flag parameters are not too clear without seeing the declaration.
This new implementation also doesn't use dynamic allocation.
combine_texturing.attach(0, depth);
combine_texturing.attach(1, color);
- Bind unbind_dtest(static_cast<DepthTest *>(0), true);
- Bind unbind_blend(static_cast<Blend *>(0), true);
+ BindRestore unbind_dtest(static_cast<DepthTest *>(0));
+ BindRestore unbind_blend(static_cast<Blend *>(0));
{
- Bind bind_fbo(fbo, true);
+ BindRestore bind_fbo(fbo);
Bind bind_tex(occlude_texturing);
Bind bind_shader(occlude_shader);
occlude_shdata.apply();
/**
RAII class for binding things. Binds the thing upon construction and unbinds
it upon destruction. If a null pointer is given, unbinds upon construction and
-does nothing upon destruction. Optionally can restore the previous binding.
+does nothing upon destruction.
*/
class Bind
{
private:
- struct Base
- {
- virtual ~Base() { }
- };
+ typedef void CleanupFunc();
+
+ CleanupFunc *cleanup;
+public:
template<typename T>
- struct Binder1: Base
- {
- const T *obj;
-
- Binder1(const T *o):
- obj(o)
- {
- if(obj)
- obj->bind();
- else
- T::unbind();
- }
-
- ~Binder1()
- {
- if(obj)
- obj->unbind();
- }
- };
-
- template<typename T, typename U>
- struct Binder2: Base
+ Bind(T *o) { init(o); }
+
+ template<typename T>
+ Bind(const T *o) { init(o); }
+
+ template<typename T>
+ Bind(const T &o) { init(&o); }
+
+private:
+ template<typename T>
+ void init(const T *o)
{
- const T *obj;
- const U *old;
-
- Binder2(const T *o, const U *l):
- obj(o),
- old(l)
- {
- if(obj)
- obj->bind();
- else
- T::unbind();
- }
-
- ~Binder2()
- {
- if(old)
- old->bind();
- else if(obj)
- obj->unbind();
- }
- };
-
- Base *binder;
+ cleanup = (o ? &unbind<T> : 0);
+ if(o)
+ o->bind();
+ else
+ T::unbind();
+ }
+
+public:
+ ~Bind()
+ { if(cleanup) cleanup(); }
+
+private:
+ template<typename T>
+ static void unbind()
+ { T::unbind(); }
+};
+
+
+/**
+Similar to Bind, but restores previous binding upon destruction.
+*/
+class BindRestore
+{
+private:
+ typedef void CleanupFunc(const void *);
+
+ const void *old;
+ CleanupFunc *cleanup;
public:
template<typename T>
- Bind(const T &o, bool r = false):
- binder(r ? create(&o, T::current()) : create(&o))
- { }
+ BindRestore(T *o) { init(o); }
template<typename T>
- Bind(const T *o, bool r = false):
- binder(r ? create(o, T::current()) : create(o))
- { }
+ BindRestore(const T *o) { init(o); }
template<typename T>
- Bind(T *o, bool r = false):
- binder(r ? create(o, T::current()) : create(o))
- { }
+ BindRestore(const T &o) { init(&o); }
private:
- Bind(const Bind &);
- Bind &operator=(const Bind &);
+ template<typename T>
+ void init(T *o)
+ {
+ old = T::current();
+ cleanup = (o!=old ? &restore<T> : 0);
+ if(o)
+ o->bind();
+ else if(old)
+ T::unbind();
+ }
public:
- ~Bind() { delete binder; }
+ ~BindRestore()
+ { if(cleanup) cleanup(old); }
private:
template<typename T>
- Base *create(const T *o)
- { return new Binder1<T>(o); }
-
- template<typename T, typename U>
- Base *create(const T *o, const U *l)
- { return new Binder2<T, U>(o, l); }
+ static void restore(const void *o)
+ {
+ if(o)
+ reinterpret_cast<const T *>(o)->bind();
+ else
+ T::unbind();
+ }
};
} // namespace GL
void Bloom::render(const Texture2D &src, const Texture2D &)
{
- Bind unbind_dtest(static_cast<DepthTest *>(0), true);
- Bind unbind_blend(static_cast<Blend *>(0), true);
+ BindRestore unbind_dtest(static_cast<DepthTest *>(0));
+ BindRestore unbind_blend(static_cast<Blend *>(0));
{
Bind bind_shader(blur_shader);
blur_shdata_common.apply();
for(unsigned i=0; i<2; ++i)
{
- Bind bind_fbo(fbo[i], true);
+ BindRestore bind_fbo(fbo[i]);
Bind bind_tex(i ? tex[0] : src);
blur_shdata[i].apply();
quad.draw();
void Font::draw_string(const string &str, StringCodec::Decoder &dec, const Color &color) const
{
- Bind bind_tex(get_texture(), true);
+ BindRestore bind_tex(get_texture());
Immediate imm((TEXCOORD2, COLOR4_UBYTE, VERTEX2));
imm.color(color);
build_string(str, dec, imm);
FramebufferStatus Framebuffer::check_status() const
{
- Bind _bind(this, true);
+ BindRestore _bind(this);
return static_cast<FramebufferStatus>(glCheckFramebufferStatus(GL_FRAMEBUFFER));
}
void Framebuffer::clear(BufferBits bits)
{
- Bind _bind(this, true);
+ BindRestore _bind(this);
glClear(bits);
}
setup_frame();
const Framebuffer *out_fbo = Framebuffer::current();
- /* Binding the current object is a no-op, but this will restore the original
- FBO in case an exception is thrown. */
- Bind restore_fbo(out_fbo, true);
+ // XXX Make sure the correct FBO is restored if an exception is thrown
if(target[0])
{
void Renderbuffer::storage(PixelFormat fmt, unsigned wd, unsigned ht)
{
require_pixelformat(fmt);
- Bind _bind(this, true);
+ BindRestore _bind(this);
width = wd;
height = ht;
glRenderbufferStorage(GL_RENDERBUFFER, fmt, width, height);
static Require _req(EXT_framebuffer_multisample);
require_pixelformat(fmt);
- Bind _bind(this, true);
+ BindRestore _bind(this);
width = wd;
height = ht;
glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, fmt, width, height);
shadow_matrix.translate(-0.5, -0.5, depth_bias/size-0.5);
shadow_matrix.invert();
- Bind bind_fbo(fbo, true);
+ BindRestore bind_fbo(fbo);
Bind bind_depth(DepthTest::lequal());
fbo.clear(DEPTH_BUFFER_BIT);
renderable.render("shadow");
unsigned h = height;
get_level_size(level, w, h);
- Bind _bind(this, true);
+ BindRestore _bind(this);
glTexImage2D(target, level, ifmt, w, h, 0, fmt, type, data);
allocated |= 1<<level;
allocate(level);
- Bind _bind(this, true);
+ BindRestore _bind(this);
glTexSubImage2D(target, level, x, y, wd, ht, fmt, type, data);
}
throw incompatible_data("Texture2D::image");
PixelStore pstore = PixelStore::from_image(img);
- Bind _bind_ps(pstore, true);
+ BindRestore _bind_ps(pstore);
image(0, fmt, UNSIGNED_BYTE, img.get_data());
}
unsigned d = depth;
get_level_size(level, w, h, d);
- Bind _bind(this, true);
+ BindRestore _bind(this);
glTexImage3D(target, level, ifmt, width, height, depth, 0, fmt, type, data);
allocated |= 1<<level;
allocate(level);
- Bind _bind(this, true);
+ BindRestore _bind(this);
glTexSubImage3D(target, level, x, y, z, wd, ht, dp, fmt, type, data);
}
throw incompatible_data("Texture3D::load_image");
PixelStore pstore = PixelStore::from_image(img);
- Bind _bind_ps(pstore, true);
+ BindRestore _bind_ps(pstore);
image(0, fmt, UNSIGNED_BYTE, img.get_data());
}
if(s==0)
throw out_of_range("TextureCube::image");
- Bind _bind(this, true);
+ BindRestore _bind(this);
glTexImage2D(face, level, ifmt, s, s, 0, fmt, type, data);
// XXX Allocation should be tracked per-face, but we'll run out of bits
throw incompatible_data("TextureCube::image");
PixelStore pstore = PixelStore::from_image(img);
- Bind _bind_ps(pstore, true);
+ BindRestore _bind_ps(pstore);
image(face, 0, fmt, UNSIGNED_BYTE, img.get_data());
}