1 #include <msp/gl/extensions/arb_direct_state_access.h>
2 #include <msp/gl/extensions/arb_sampler_objects.h>
3 #include <msp/gl/extensions/arb_shadow.h>
4 #include <msp/gl/extensions/ext_texture_filter_anisotropic.h>
5 #include <msp/gl/extensions/ext_texture3d.h>
6 #include <msp/gl/extensions/khr_debug.h>
7 #include <msp/strings/format.h>
23 Require _req(ARB_sampler_objects);
24 if(ARB_direct_state_access)
25 glCreateSamplers(1, &id);
27 glGenSamplers(1, &id);
30 Sampler::Sampler(const Texture &tex):
34 if(this!=&tex.get_default_sampler())
35 throw invalid_argument("Sampler::Sampler");
42 min_filter = NEAREST_MIPMAP_LINEAR;
44 max_anisotropy = 1.0f;
48 border_color = Color(0.0f, 0.0f, 0.0f, 0.0f);
54 void Sampler::update_parameter(int mask) const
64 if(!ARB_direct_state_access && TexUnit::current().get_texture()!=owner)
66 TexUnit *unit = TexUnit::find_unit(owner);
78 set_parameter_i(GL_TEXTURE_MIN_FILTER, min_filter);
80 set_parameter_i(GL_TEXTURE_MAG_FILTER, mag_filter);
81 if(mask&MAX_ANISOTROPY)
82 set_parameter_f(GL_TEXTURE_MAX_ANISOTROPY_EXT, max_anisotropy);
84 set_parameter_i(GL_TEXTURE_WRAP_S, wrap_s);
86 set_parameter_i(GL_TEXTURE_WRAP_T, wrap_t);
88 set_parameter_i(GL_TEXTURE_WRAP_R, wrap_r);
90 set_parameter_fv(GL_TEXTURE_BORDER_COLOR, &border_color.r);
93 set_parameter_i(GL_TEXTURE_COMPARE_MODE, (compare ? GL_COMPARE_R_TO_TEXTURE : GL_NONE));
95 set_parameter_i(GL_TEXTURE_COMPARE_FUNC, cmp_func);
99 void Sampler::set_parameter_i(unsigned param, int value) const
102 glSamplerParameteri(id, param, value);
103 else if(ARB_direct_state_access)
104 glTextureParameteri(owner->get_id(), param, value);
106 glTexParameteri(owner->get_target(), param, value);
109 void Sampler::set_parameter_f(unsigned param, float value) const
112 glSamplerParameterf(id, param, value);
113 else if(ARB_direct_state_access)
114 glTextureParameterf(owner->get_id(), param, value);
116 glTexParameterf(owner->get_target(), param, value);
119 void Sampler::set_parameter_fv(unsigned param, const float *value) const
122 glSamplerParameterfv(id, param, value);
123 else if(ARB_direct_state_access)
124 glTextureParameterfv(owner->get_id(), param, value);
126 glTexParameterfv(owner->get_target(), param, value);
129 void Sampler::set_min_filter(TextureFilter f)
132 update_parameter(MIN_FILTER);
135 void Sampler::set_mag_filter(TextureFilter f)
138 update_parameter(MAG_FILTER);
141 void Sampler::set_filter(TextureFilter f)
144 set_mag_filter(f==NEAREST ? NEAREST : LINEAR);
147 void Sampler::set_max_anisotropy(float a)
150 throw invalid_argument("Sampler::set_max_anisotropy");
152 static Require _req(EXT_texture_filter_anisotropic);
154 if(EXT_texture_filter_anisotropic)
155 update_parameter(MAX_ANISOTROPY);
158 void Sampler::set_wrap(TextureWrap w)
166 void Sampler::set_wrap_s(TextureWrap w)
169 update_parameter(WRAP_S);
172 void Sampler::set_wrap_t(TextureWrap w)
175 update_parameter(WRAP_T);
178 void Sampler::set_wrap_r(TextureWrap w)
180 static Require _req(EXT_texture3D);
182 update_parameter(WRAP_R);
185 void Sampler::set_border_color(const Color &c)
188 update_parameter(BORDER_COLOR);
191 void Sampler::disable_compare()
194 update_parameter(COMPARE);
197 void Sampler::set_compare(Predicate f)
199 static Require _req(ARB_shadow);
202 update_parameter(COMPARE);
205 void Sampler::bind_to(unsigned i) const
207 TexUnit &unit = TexUnit::get_unit(i);
208 if(owner && owner!=unit.get_texture())
209 throw invalid_operation("Sampler::bind_to");
211 const Sampler *cur = unit.get_sampler();
212 if(unit.set_sampler(this))
214 if(!owner || (cur && cur->id))
215 glBindSampler(i, id);
219 update_parameter(dirty_params);
225 const Sampler *Sampler::current(unsigned i)
227 return TexUnit::get_unit(i).get_sampler();
230 void Sampler::unbind_from(unsigned i)
232 TexUnit &unit = TexUnit::get_unit(i);
233 const Sampler *cur = unit.get_sampler();
234 if(unit.set_sampler(0) && cur->id)
238 void Sampler::unload()
240 if(owner && !owner->get_id())
242 if(min_filter!=NEAREST_MIPMAP_LINEAR)
243 dirty_params |= MIN_FILTER;
244 if(mag_filter!=LINEAR)
245 dirty_params |= MAG_FILTER;
246 if(max_anisotropy!=1.0f)
247 dirty_params |= MAX_ANISOTROPY;
249 dirty_params |= WRAP_S;
251 dirty_params |= WRAP_T;
253 dirty_params |= WRAP_R;
254 if(compare || cmp_func!=LEQUAL)
255 dirty_params |= COMPARE;
259 void Sampler::set_debug_name(const string &name)
263 glObjectLabel(GL_SAMPLER, id, name.size(), name.c_str());
270 Sampler::Loader::Loader(Sampler &s):
271 DataFile::ObjectLoader<Sampler>(s)
273 add("border_color", &Loader::border_color);
274 add("compare", &Loader::compare);
275 add("filter", &Loader::filter);
276 add("mag_filter", &Loader::mag_filter);
277 add("max_anisotropy", &Loader::max_anisotropy);
278 add("min_filter", &Loader::min_filter);
279 add("wrap", &Loader::wrap);
280 add("wrap_r", &Loader::wrap_r);
281 add("wrap_s", &Loader::wrap_s);
282 add("wrap_t", &Loader::wrap_t);
285 void Sampler::Loader::border_color(float r, float g, float b, float a)
287 obj.set_border_color(Color(r, g, b, a));
290 void Sampler::Loader::compare(Predicate c)
295 void Sampler::Loader::filter(TextureFilter f)
300 void Sampler::Loader::mag_filter(TextureFilter f)
302 obj.set_mag_filter(f);
305 void Sampler::Loader::max_anisotropy(float a)
307 obj.set_max_anisotropy(a);
310 void Sampler::Loader::min_filter(TextureFilter f)
312 obj.set_min_filter(f);
315 void Sampler::Loader::wrap(TextureWrap w)
320 void Sampler::Loader::wrap_r(TextureWrap w)
325 void Sampler::Loader::wrap_s(TextureWrap w)
330 void Sampler::Loader::wrap_t(TextureWrap w)
336 bool is_mipmapped(TextureFilter filter)
338 return (filter==NEAREST_MIPMAP_NEAREST || filter==NEAREST_MIPMAP_LINEAR ||
339 filter==LINEAR_MIPMAP_NEAREST || filter==LINEAR_MIPMAP_LINEAR);
342 void operator>>(const LexicalConverter &c, TextureFilter &tf)
344 if(c.get()=="NEAREST")
346 else if(c.get()=="LINEAR")
348 else if(c.get()=="NEAREST_MIPMAP_NEAREST")
349 tf = NEAREST_MIPMAP_NEAREST;
350 else if(c.get()=="NEAREST_MIPMAP_LINEAR")
351 tf = NEAREST_MIPMAP_LINEAR;
352 else if(c.get()=="LINEAR_MIPMAP_NEAREST")
353 tf = LINEAR_MIPMAP_NEAREST;
354 else if(c.get()=="LINEAR_MIPMAP_LINEAR")
355 tf = LINEAR_MIPMAP_LINEAR;
357 throw lexical_error(format("conversion of '%s' to TextureFilter", c.get()));
360 void operator>>(const LexicalConverter &c, TextureWrap &tw)
362 if(c.get()=="REPEAT")
364 else if(c.get()=="CLAMP_TO_EDGE")
366 else if(c.get()=="CLAMP_TO_BORDER")
367 tw = CLAMP_TO_BORDER;
368 else if(c.get()=="MIRRORED_REPEAT")
369 tw = MIRRORED_REPEAT;
371 throw lexical_error(format("conversion of '%s' to TextureWrap", c.get()));