namespace Msp {
namespace GL {
+Sampler::Sampler():
+ owner(0)
+{
+ init();
+
+ Require _req(ARB_sampler_objects);
+ if(ARB_direct_state_access)
+ glCreateSamplers(1, &id);
+ else
+ glGenSamplers(1, &id);
+}
+
Sampler::Sampler(const Texture &tex):
id(0),
owner(&tex)
void Sampler::update_parameter(int mask) const
{
- if(!owner->get_id() || (!ARB_direct_state_access && TexUnit::current().get_texture()!=owner))
+ if(owner)
{
- TexUnit *unit = TexUnit::find_unit(owner);
- if(!unit)
+ if(!owner->get_id())
{
dirty_params |= mask;
return;
}
- unit->bind();
+ if(!ARB_direct_state_access && TexUnit::current().get_texture()!=owner)
+ {
+ TexUnit *unit = TexUnit::find_unit(owner);
+ if(!unit)
+ {
+ dirty_params |= mask;
+ return;
+ }
+
+ unit->bind();
+ }
}
if(mask&MIN_FILTER)
void Sampler::set_parameter_i(unsigned param, int value) const
{
- if(ARB_direct_state_access)
+ if(id)
+ glSamplerParameteri(id, param, value);
+ else if(ARB_direct_state_access)
glTextureParameteri(owner->get_id(), param, value);
else
glTexParameteri(owner->get_target(), param, value);
void Sampler::set_parameter_f(unsigned param, float value) const
{
- if(ARB_direct_state_access)
+ if(id)
+ glSamplerParameterf(id, param, value);
+ else if(ARB_direct_state_access)
glTextureParameterf(owner->get_id(), param, value);
else
glTexParameterf(owner->get_target(), param, value);
void Sampler::bind_to(unsigned i) const
{
TexUnit &unit = TexUnit::get_unit(i);
- if(owner!=unit.get_texture())
+ if(owner && owner!=unit.get_texture())
throw invalid_operation("Sampler::bind_to");
- if(dirty_params)
+ const Sampler *cur = unit.get_sampler();
+ if(unit.set_sampler(this))
{
- update_parameter(dirty_params);
- dirty_params = 0;
+ if(!owner || (cur && cur->id))
+ glBindSampler(i, id);
+
+ if(dirty_params)
+ {
+ update_parameter(dirty_params);
+ dirty_params = 0;
+ }
}
}
+const Sampler *Sampler::current(unsigned i)
+{
+ return TexUnit::get_unit(i).get_sampler();
+}
+
+void Sampler::unbind_from(unsigned i)
+{
+ TexUnit &unit = TexUnit::get_unit(i);
+ const Sampler *cur = unit.get_sampler();
+ if(unit.set_sampler(0) && cur->id)
+ glBindSampler(i, 0);
+}
+
void Sampler::unload()
{
// TODO check which params actually need refreshing
void bind() const { bind_to(0); }
void bind_to(unsigned) const;
+ static const Sampler *current(unsigned = 0);
+ static void unbind() { unbind_from(0); }
+ static void unbind_from(unsigned);
+
void unload();
};
glBindTexture(target, id);
}
- default_sampler.bind_to(i);
+ if(!unit.get_sampler())
+ default_sampler.bind_to(i);
}
}
unit.bind();
glBindTexture(cur->target, 0);
}
+
+ if(unit.get_sampler()==&cur->default_sampler)
+ Sampler::unbind_from(i);
}
}
{
unsigned w = img.get_width();
unsigned h = img.get_height();
- unsigned d = 1;
- if(depth)
- {
- if(h%depth)
- throw incompatible_data("Texture3D::load_image");
- h /= depth;
- d = depth;
- }
- else
- {
- if(h%w)
- throw incompatible_data("Texture3D::load_image");
- d = h/w;
- h = w;
- }
+ if(h%w)
+ throw incompatible_data("Texture3D::load_image");
+ unsigned d = h/w;
+ h = w;
PixelFormat fmt = pixelformat_from_image(img);
if(width==0)
max_unit -= min(max_unit/4, 8U);
unsigned initial_unit = (name_hint.empty() ? 0 : hash32(name_hint)%max_unit);
unsigned unit = initial_unit;
- while(get_attached_texture(unit))
+ while(get_attached_texture(unit) || get_attached_sampler(unit))
{
unit = (unit+1)%max_unit;
if(unit==initial_unit)
return unit;
}
-void Texturing::attach(unsigned attch, const Texture &tex)
+void Texturing::attach(unsigned attch, const Texture &tex, const Sampler *samp)
{
- set_attachment(attch, &tex);
+ set_attachment(attch, &tex, samp);
+}
+
+void Texturing::attach(unsigned attch, const Sampler &samp)
+{
+ set_attachment(attch, 0, &samp);
}
void Texturing::detach(unsigned attch)
{
- set_attachment(attch, 0);
+ set_attachment(attch, 0, 0);
}
-void Texturing::set_attachment(unsigned unit, const Texture *tex)
+void Texturing::set_attachment(unsigned unit, const Texture *tex, const Sampler *samp)
{
if(unit>=TexUnit::get_n_units())
throw out_of_range("Texturing::set_attachment");
- if(tex)
+ if(tex || samp)
{
vector<Attachment>::iterator i;
for(i=attachments.begin(); (i!=attachments.end() && i->unit<=unit); ++i)
if(i->unit==unit)
{
i->texture = tex;
+ i->sampler = samp;
if(current()==this)
- tex->bind_to(unit);
+ bind_attachment(*i);
return;
}
- attachments.insert(i, Attachment(unit, tex));
+ attachments.insert(i, Attachment(unit, tex, samp));
if(current()==this)
tex->bind_to(unit);
}
{
attachments.erase(i);
if(current()==this)
- Texture::unbind_from(unit);
+ unbind_attachment(unit);
return;
}
}
return 0;
}
+const Sampler *Texturing::get_attached_sampler(unsigned unit) const
+{
+ for(vector<Attachment>::const_iterator i=attachments.begin(); (i!=attachments.end() && i->unit<=unit); ++i)
+ if(i->unit==unit)
+ return i->sampler;
+ return 0;
+}
+
void Texturing::bind() const
{
const Texturing *old = current();
{
if(i!=attachments.end() && (j==old->attachments.end() || i->unit<=j->unit))
{
- i->texture->bind_to(i->unit);
+ bind_attachment(*i);
if(j!=old->attachments.end() && j->unit==i->unit)
++j;
++i;
}
else
{
- Texture::unbind_from(j->unit);
+ unbind_attachment(j->unit);
++j;
}
}
else
{
for(vector<Attachment>::const_iterator i=attachments.begin(); i!=attachments.end(); ++i)
- i->texture->bind_to(i->unit);
+ bind_attachment(*i);
}
}
}
+void Texturing::bind_attachment(const Attachment &attch) const
+{
+ if(attch.sampler)
+ attch.sampler->bind_to(attch.unit);
+ else
+ Sampler::unbind_from(attch.unit);
+ attch.texture->bind_to(attch.unit);
+}
+
void Texturing::unbind()
{
const Texturing *old = current();
if(set_current(0))
{
for(vector<Attachment>::const_iterator i=old->attachments.begin(); i!=old->attachments.end(); ++i)
- Texture::unbind_from(i->unit);
+ unbind_attachment(i->unit);
}
}
+void Texturing::unbind_attachment(unsigned unit)
+{
+ Texture::unbind_from(unit);
+ Sampler::unbind_from(unit);
+}
+
-Texturing::Attachment::Attachment(unsigned u, const Texture *t):
+Texturing::Attachment::Attachment(unsigned u, const Texture *t, const Sampler *s):
unit(u),
- texture(t)
+ texture(t),
+ sampler(s)
{ }
} // namespace GL
{
unsigned unit;
const Texture *texture;
+ const Sampler *sampler;
- Attachment(unsigned, const Texture *);
+ Attachment(unsigned, const Texture *, const Sampler *);
};
std::vector<Attachment> attachments;
~Texturing();
int find_free_unit(const std::string & = std::string()) const;
- void attach(unsigned, const Texture &);
+ void attach(unsigned, const Texture &, const Sampler * = 0);
+ void attach(unsigned, const Sampler &);
void detach(unsigned);
private:
- void set_attachment(unsigned, const Texture *);
+ void set_attachment(unsigned, const Texture *, const Sampler *);
public:
const Texture *get_attached_texture(unsigned) const;
+ const Sampler *get_attached_sampler(unsigned) const;
void bind() const;
static void unbind();
+
+private:
+ void bind_attachment(const Attachment &) const;
+ static void unbind_attachment(unsigned);
};
} // namespace GL
#include <msp/gl/extensions/arb_vertex_shader.h>
#include "gl.h"
#include "misc.h"
+#include "texture.h"
#include "texunit.h"
using namespace std;
TexUnit *TexUnit::cur_unit = 0;
TexUnit::TexUnit():
- texture(0)
+ texture(0),
+ sampler(0)
{ }
bool TexUnit::set_texture(const Texture *tex)
return result;
}
+bool TexUnit::set_sampler(const Sampler *samp)
+{
+ bool result = (samp!=sampler);
+ sampler = samp;
+ return result;
+}
+
void TexUnit::bind()
{
if(cur_unit!=this && (cur_unit || index))
namespace Msp {
namespace GL {
-class TexEnv;
-class TexGen;
+class Sampler;
class Texture;
/**
private:
unsigned index;
const Texture *texture;
+ const Sampler *sampler;
static std::vector<TexUnit> units;
static TexUnit *cur_unit;
unsigned get_index() const { return index; }
bool set_texture(const Texture *);
const Texture *get_texture() const { return texture; }
+ bool set_sampler(const Sampler *);
+ const Sampler *get_sampler() const { return sampler; }
void bind();
static unsigned get_n_units();