}
public:
- const T *current() const { return cur_obj; }
+ static const T *current() { return cur_obj; }
};
template<typename T>
/**
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.
+does nothing upon destruction. Optionally can restore the previous binding.
*/
class Bind
{
};
template<typename T>
- struct Binder: Base
+ struct Binder1: Base
{
- const T &obj;
+ const T *obj;
+
+ Binder1(const T *o):
+ obj(o)
+ {
+ if(obj)
+ obj->bind();
+ else
+ T::unbind();
+ }
+
+ ~Binder1()
+ {
+ if(obj)
+ obj->unbind();
+ }
+ };
- Binder(const T &o): obj(o) { obj.bind(); }
- ~Binder() { obj.unbind(); }
+ template<typename T, typename U>
+ struct Binder2: Base
+ {
+ 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;
public:
template<typename T>
- Bind(const T &o): binder(new Binder<T>(o)) { }
-
- template<typename T>
- Bind(const T *o): binder(o ? new Binder<T>(*o) : 0) { if(!o) T::unbind(); }
+ Bind(const T *o, bool r = false):
+ binder(r ? create(o, T::current()) : create(o))
+ { }
private:
Bind(const Bind &);
public:
~Bind() { delete binder; }
+
+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); }
};
} // namespace GL
void Framebuffer::bind() const
{
- if(!cur_fbo)
- get(GL_VIEWPORT, sys_viewport);
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, id);
- cur_fbo = this;
- if(width && height)
- viewport(0, 0, width, height);
+ const Framebuffer *old = current();
+ if(set_current(this))
+ {
+ if(!old)
+ get(GL_VIEWPORT, sys_viewport);
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, id);
+ if(width && height)
+ viewport(0, 0, width, height);
+ }
}
void Framebuffer::attach(FramebufferAttachment attch, Renderbuffer &rbuf)
{
- maybe_bind();
+ bind();
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, attch, GL_RENDERBUFFER_EXT, rbuf.get_id());
get_or_create_attachment(attch) = rbuf;
check_size();
void Framebuffer::attach(FramebufferAttachment attch, Texture2D &tex, int level)
{
- maybe_bind();
+ bind();
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attch, tex.get_target(), tex.get_id(), level);
get_or_create_attachment(attch) = tex;
check_size();
void Framebuffer::detach(FramebufferAttachment attch)
{
- maybe_bind();
+ bind();
for(vector<Attachment>::iterator i=attachments.begin(); i!=attachments.end(); ++i)
if(i->attachment==attch)
{
FramebufferStatus Framebuffer::check_status() const
{
- maybe_bind();
+ bind();
return static_cast<FramebufferStatus>(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
}
-const Framebuffer *Framebuffer::current()
-{
- return cur_fbo;
-}
-
void Framebuffer::unbind()
{
- if(cur_fbo)
+ if(set_current(0))
{
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
- cur_fbo = 0;
viewport(sys_viewport[0], sys_viewport[1], sys_viewport[2], sys_viewport[3]);
}
}
-void Framebuffer::maybe_bind() const
-{
- if(cur_fbo!=this)
- bind();
-}
-
Framebuffer::Attachment &Framebuffer::get_or_create_attachment(FramebufferAttachment attch)
{
for(vector<Attachment>::iterator i=attachments.begin(); i!=attachments.end(); ++i)
width = tex->get_width();
height = tex->get_height();
}
- if(cur_fbo==this)
+ if(current()==this)
viewport(0, 0, width, height);
}
}
-const Framebuffer *Framebuffer::cur_fbo = 0;
int Framebuffer::sys_viewport[4] = { 0, 0, 1, 1 };
#define MSP_GL_FRAMEBUFFER_H_
#include <vector>
+#include "bindable.h"
#include "gl.h"
namespace Msp {
Requires the GL_EXT_framebuffer_object extension.
*/
-class Framebuffer
+class Framebuffer: public Bindable<Framebuffer>
{
private:
struct Attachment
unsigned width;
unsigned height;
- static const Framebuffer *cur_fbo;
static int sys_viewport[4];
public:
*/
FramebufferStatus check_status() const;
- static const Framebuffer *current();
static void unbind();
private:
void maybe_bind() const;
void Lighting::bind() const
{
- if(current!=this)
- {
- enable(LIGHTING);
- glLightModelfv(GL_LIGHT_MODEL_AMBIENT, &ambient.r);
- for(unsigned i=0; i<lights.size(); ++i)
- if(lights[i])
- lights[i]->bind_to(i);
- current = this;
- }
+ if(!set_current(this))
+ return;
+
+ enable(LIGHTING);
+ glLightModelfv(GL_LIGHT_MODEL_AMBIENT, &ambient.r);
+ for(unsigned i=0; i<lights.size(); ++i)
+ if(lights[i])
+ lights[i]->bind_to(i);
}
void Lighting::unbind()
{
- if(current)
- {
- for(unsigned i=0; i<current->lights.size(); ++i)
- if(current->lights[i])
- {
- Light::activate(i);
- Light::unbind();
- }
- disable(LIGHTING);
- current = 0;
- }
-}
+ const Lighting *old = current();
+ if(!set_current(0))
+ return;
-const Lighting *Lighting::current = 0;
+ for(unsigned i=0; i<old->lights.size(); ++i)
+ if(old->lights[i])
+ {
+ Light::activate(i);
+ Light::unbind();
+ }
+ disable(LIGHTING);
+}
} // namespace GL
} // namespace Msp
#define MSP_GL_LIGHTING_H_
#include <vector>
+#include "bindable.h"
#include "color.h"
#include "gl.h"
/**
Encapsulates global lighting parameters and a number of individual lights.
*/
-class Lighting
+class Lighting: public Bindable<Lighting>
{
private:
Color ambient;
std::vector<const Light *> lights;
- static const Lighting *current;
-
public:
Lighting();
void Material::bind() const
{
- if(current!=this)
+ if(set_current(this))
{
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, &ambient.r);
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, &diffuse.r);
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &specular.r);
glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, &emission.r);
glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, shininess);
- current = this;
}
}
void Material::unbind()
{
- current = 0;
+ set_current(0);
}
-const Material *Material::current = 0;
-
Material::Loader::Loader(Material &m):
DataFile::ObjectLoader<Material>(m)
#define MSP_GL_MATERIAL_H_
#include <msp/datafile/objectloader.h>
+#include "bindable.h"
#include "color.h"
namespace Msp {
Stores OpenGL material properties. Since OpenGL does not support material
objects, application of material is done with several calls to glMaterial.
*/
-class Material
+class Material: public Bindable<Material>
{
public:
class Loader: public DataFile::ObjectLoader<Material>
void bind() const;
static void unbind();
-private:
- static const Material *current;
};
} // namespace GL
if(!pass)
return;
- Bind bind(*pass);
+ Bind bind(pass);
meshes[0]->draw();
}
if(!pass)
return;
- Bind bind(*pass);
+ Bind bind(pass);
render_instance(inst, tag);
meshes[0]->draw();
}
const RenderPass *Object::get_pass(const Tag &tag) const
{
- if(!technique->has_pass(tag))
+ if(!technique || !technique->has_pass(tag))
return 0;
return &technique->get_pass(tag);
}
if(!pass)
return;
- Bind bind(*pass);
+ Bind bind(pass);
for(Iter i=begin; i!=end; ++i)
render_instance(**i, tag);
}
if(!linked)
throw InvalidState("Program is not linked");
+ if(!set_current(this))
+ return;
+
glUseProgramObjectARB(id);
- cur_prog = this;
}
int Program::get_uniform_location(const string &n) const
void Program::unbind()
{
- if(cur_prog)
- {
- glUseProgramObjectARB(0);
- cur_prog = 0;
- }
-}
+ if(!set_current(0))
+ return;
-void Program::maybe_bind()
-{
- if(cur_prog!=this)
- bind();
+ glUseProgramObjectARB(0);
}
-const Program *Program::cur_prog = 0;
-
Program::Loader::Loader(Program &p):
DataFile::ObjectLoader<Program>(p)
#include <list>
#include <string>
#include <msp/datafile/objectloader.h>
+#include "bindable.h"
#include "gl.h"
namespace Msp {
class Shader;
-class Program
+class Program: public Bindable<Program>
{
private:
unsigned id;
bool del_shaders;
bool linked;
- static const Program *cur_prog;
-
public:
class Loader: public DataFile::ObjectLoader<Program>
{
int get_uniform_location(const std::string &) const;
static void unbind();
-
-private:
- void maybe_bind();
};
} // namespace GL
glDeleteRenderbuffersEXT(1, &id);
}
-void Renderbuffer::bind() const
-{
- glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, id);
-}
-
void Renderbuffer::storage(PixelFormat fmt, unsigned w, unsigned h)
{
bind();
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, fmt, width, height);
}
+void Renderbuffer::bind() const
+{
+ if(set_current(this))
+ glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, id);
+}
+
+void Renderbuffer::unbind()
+{
+ if(set_current(0))
+ glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
+}
+
} // namespace GL
} // namespace Msp
#ifndef MSP_GL_RENDERBUFFER_H_
#define MSP_GL_RENDERBUFFER_H_
+#include "bindable.h"
#include "pixelformat.h"
namespace Msp {
Requires the GL_EXT_framebuffer_object extension.
*/
-class Renderbuffer
+class Renderbuffer: public Bindable<Renderbuffer>
{
private:
unsigned id;
unsigned get_width() const { return width; }
unsigned get_height() const { return height; }
+ void storage(PixelFormat fmt, unsigned width, unsigned height);
+
void bind() const;
- void storage(PixelFormat fmt, unsigned width, unsigned height);
+ static void unbind();
};
} // namespace GL
namespace Msp {
namespace GL {
-const RenderPass *RenderPass::current = 0;
-
RenderPass::RenderPass():
shprog(0),
shdata(0),
void RenderPass::bind() const
{
- if(this==current)
+ const RenderPass *old = current();
+ if(!set_current(this))
return;
- const RenderPass *old = current;
- current = this;
-
if(shprog)
{
shprog->bind();
shdata->apply();
}
- else if(old && !old->shprog)
+ else if(old && old->shprog)
GL::Program::unbind();
if(material)
material->bind();
- else if(old && !old->material)
+ else if(old && old->material)
GL::Material::unbind();
for(unsigned i=0; i<textures.size(); ++i)
void RenderPass::unbind()
{
- if(current)
- {
- if(current->shprog)
- GL::Program::unbind();
+ const RenderPass *old = current();
+ if(!set_current(0))
+ return;
- if(current->material)
- GL::Material::unbind();
+ if(old->shprog)
+ GL::Program::unbind();
- for(unsigned i=current->textures.size(); i--; )
- GL::Texture::unbind_from(i);
+ if(old->material)
+ GL::Material::unbind();
- current = 0;
- }
+ for(unsigned i=old->textures.size(); i--; )
+ GL::Texture::unbind_from(i);
}
#define MSP_GL_RENDERPASS_H_
#include <msp/datafile/objectloader.h>
+#include "bindable.h"
namespace Msp {
namespace GL {
Encapsulates the data that determines the appearance of a rendered surface.
This includes shader and data for it, material and textures.
*/
-class RenderPass
+class RenderPass: public Bindable<RenderPass>
{
public:
class Loader: public DataFile::CollectionObjectLoader<RenderPass>
const Material *material;
std::vector<TextureSlot> textures;
- static const RenderPass *current;
-
RenderPass &operator=(const RenderPass &);
public:
RenderPass();
bool write;
Predicate pred;
- static const DepthTest *current;
-
public:
DepthTest();
DepthTest(Predicate, bool = true);