+#include <msp/core/hash.h>
#include "texture.h"
#include "texturing.h"
#include "texunit.h"
unbind();
}
-void Texturing::attach(unsigned attch, const Texture &tex)
+int Texturing::find_free_unit(const string &name_hint) const
{
- set_attachment(attch, &tex);
+ unsigned max_unit = TexUnit::get_n_units();
+ // Leave some space for effect textures
+ 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) || get_attached_sampler(unit))
+ {
+ unit = (unit+1)%max_unit;
+ if(unit==initial_unit)
+ return -1;
+ }
+
+ return unit;
}
-void Texturing::detach(unsigned attch)
+void Texturing::attach(unsigned attch, const Texture &tex, const Sampler *samp)
{
- set_attachment(attch, 0);
+ set_attachment(attch, &tex, samp);
}
-void Texturing::set_attachment(unsigned attch, const Texture *tex)
+void Texturing::attach(unsigned attch, const Sampler &samp)
{
- if(attch>=TexUnit::get_n_units())
- throw out_of_range("Texturing::set_attachment");
+ set_attachment(attch, 0, &samp);
+}
- if(attachments.size()<=attch)
- attachments.resize(attch+1);
+void Texturing::detach(unsigned attch)
+{
+ set_attachment(attch, 0, 0);
+}
- attachments[attch].tex = 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(current()==this)
- bind_attachment(attch);
+ 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)
+ bind_attachment(*i);
+ return;
+ }
+
+ attachments.insert(i, Attachment(unit, tex, samp));
+ if(current()==this)
+ tex->bind_to(unit);
+ }
+ else
+ {
+ for(vector<Attachment>::iterator i=attachments.begin(); (i!=attachments.end() && i->unit<=unit); ++i)
+ if(i->unit==unit)
+ {
+ attachments.erase(i);
+ if(current()==this)
+ unbind_attachment(unit);
+ return;
+ }
+ }
}
-void Texturing::bind_attachment(unsigned i) const
+const Texture *Texturing::get_attached_texture(unsigned unit) const
{
- const Attachment &attch = attachments[i];
- if(attch.tex)
- attch.tex->bind_to(i);
- else
- Texture::unbind_from(i);
+ for(vector<Attachment>::const_iterator i=attachments.begin(); (i!=attachments.end() && i->unit<=unit); ++i)
+ if(i->unit==unit)
+ return i->texture;
+ return 0;
}
-void Texturing::unbind_attachment(unsigned i)
+const Sampler *Texturing::get_attached_sampler(unsigned unit) const
{
- Texture::unbind_from(i);
+ 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(set_current(this))
{
- for(unsigned i=0; i<attachments.size(); ++i)
- bind_attachment(i);
if(old)
{
- for(unsigned i=attachments.size(); i<old->attachments.size(); ++i)
- unbind_attachment(i);
+ vector<Attachment>::const_iterator i = attachments.begin();
+ vector<Attachment>::const_iterator j = old->attachments.begin();
+ while(i!=attachments.end() || j!=old->attachments.end())
+ {
+ if(i!=attachments.end() && (j==old->attachments.end() || i->unit<=j->unit))
+ {
+ bind_attachment(*i);
+ if(j!=old->attachments.end() && j->unit==i->unit)
+ ++j;
+ ++i;
+ }
+ else
+ {
+ unbind_attachment(j->unit);
+ ++j;
+ }
+ }
+ }
+ else
+ {
+ for(vector<Attachment>::const_iterator i=attachments.begin(); i!=attachments.end(); ++i)
+ 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(unsigned i=old->attachments.size(); i--;)
- unbind_attachment(i);
+ for(vector<Attachment>::const_iterator i=old->attachments.begin(); i!=old->attachments.end(); ++i)
+ unbind_attachment(i->unit);
}
}
+void Texturing::unbind_attachment(unsigned unit)
+{
+ Texture::unbind_from(unit);
+ Sampler::unbind_from(unit);
+}
+
-Texturing::Attachment::Attachment():
- tex(0)
+Texturing::Attachment::Attachment(unsigned u, const Texture *t, const Sampler *s):
+ unit(u),
+ texture(t),
+ sampler(s)
{ }
} // namespace GL