]> git.tdb.fi Git - libs/gl.git/blob - source/core/sampler.cpp
93b3b5c9f702e69e091ffbd480c438d7fe8f695c
[libs/gl.git] / source / core / sampler.cpp
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>
8 #include "error.h"
9 #include "sampler.h"
10 #include "texture.h"
11 #include "texunit.h"
12
13 using namespace std;
14
15 namespace Msp {
16 namespace GL {
17
18 Sampler::Sampler():
19         owner(0)
20 {
21         init();
22
23         Require _req(ARB_sampler_objects);
24         if(ARB_direct_state_access)
25                 glCreateSamplers(1, &id);
26         else
27                 glGenSamplers(1, &id);
28 }
29
30 Sampler::Sampler(const Texture &tex):
31         id(0),
32         owner(&tex)
33 {
34         if(this!=&tex.get_default_sampler())
35                 throw invalid_argument("Sampler::Sampler");
36
37         init();
38 }
39
40 void Sampler::init()
41 {
42         min_filter = NEAREST_MIPMAP_LINEAR;
43         mag_filter = LINEAR;
44         max_anisotropy = 1.0f;
45         wrap_s = REPEAT;
46         wrap_t = REPEAT;
47         wrap_r = REPEAT;
48         border_color = Color(0.0f, 0.0f, 0.0f, 0.0f);
49         compare = false;
50         cmp_func = LEQUAL;
51         dirty_params = 0;
52 }
53
54 void Sampler::update_parameter(int mask) const
55 {
56         if(owner)
57         {
58                 if(!owner->get_id())
59                 {
60                         dirty_params |= mask;
61                         return;
62                 }
63
64                 if(!ARB_direct_state_access && TexUnit::current().get_texture()!=owner)
65                 {
66                         TexUnit *unit = TexUnit::find_unit(owner);
67                         if(!unit)
68                         {
69                                 dirty_params |= mask;
70                                 return;
71                         }
72
73                         unit->bind();
74                 }
75         }
76
77         if(mask&MIN_FILTER)
78                 set_parameter_i(GL_TEXTURE_MIN_FILTER, min_filter);
79         if(mask&MAG_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);
83         if(mask&WRAP_S)
84                 set_parameter_i(GL_TEXTURE_WRAP_S, wrap_s);
85         if(mask&WRAP_T)
86                 set_parameter_i(GL_TEXTURE_WRAP_T, wrap_t);
87         if(mask&WRAP_R)
88                 set_parameter_i(GL_TEXTURE_WRAP_R, wrap_r);
89         if(mask&BORDER_COLOR)
90                 set_parameter_fv(GL_TEXTURE_BORDER_COLOR, &border_color.r);
91         if(mask&COMPARE)
92         {
93                 set_parameter_i(GL_TEXTURE_COMPARE_MODE, (compare ? GL_COMPARE_R_TO_TEXTURE : GL_NONE));
94                 if(compare)
95                         set_parameter_i(GL_TEXTURE_COMPARE_FUNC, cmp_func);
96         }
97 }
98
99 void Sampler::set_parameter_i(unsigned param, int value) const
100 {
101         if(id)
102                 glSamplerParameteri(id, param, value);
103         else if(ARB_direct_state_access)
104                 glTextureParameteri(owner->get_id(), param, value);
105         else
106                 glTexParameteri(owner->get_target(), param, value);
107 }
108
109 void Sampler::set_parameter_f(unsigned param, float value) const
110 {
111         if(id)
112                 glSamplerParameterf(id, param, value);
113         else if(ARB_direct_state_access)
114                 glTextureParameterf(owner->get_id(), param, value);
115         else
116                 glTexParameterf(owner->get_target(), param, value);
117 }
118
119 void Sampler::set_parameter_fv(unsigned param, const float *value) const
120 {
121         if(id)
122                 glSamplerParameterfv(id, param, value);
123         else if(ARB_direct_state_access)
124                 glTextureParameterfv(owner->get_id(), param, value);
125         else
126                 glTexParameterfv(owner->get_target(), param, value);
127 }
128
129 void Sampler::set_min_filter(TextureFilter f)
130 {
131         min_filter = f;
132         update_parameter(MIN_FILTER);
133 }
134
135 void Sampler::set_mag_filter(TextureFilter f)
136 {
137         mag_filter = f;
138         update_parameter(MAG_FILTER);
139 }
140
141 void Sampler::set_filter(TextureFilter f)
142 {
143         set_min_filter(f);
144         set_mag_filter(f==NEAREST ? NEAREST : LINEAR);
145 }
146
147 void Sampler::set_max_anisotropy(float a)
148 {
149         if(a<1.0f)
150                 throw invalid_argument("Sampler::set_max_anisotropy");
151         else if(a>1.0f)
152                 static Require _req(EXT_texture_filter_anisotropic);
153         max_anisotropy = a;
154         if(EXT_texture_filter_anisotropic)
155                 update_parameter(MAX_ANISOTROPY);
156 }
157
158 void Sampler::set_wrap(TextureWrap w)
159 {
160         set_wrap_s(w);
161         set_wrap_t(w);
162         if(EXT_texture3D)
163                 set_wrap_r(w);
164 }
165
166 void Sampler::set_wrap_s(TextureWrap w)
167 {
168         wrap_s = w;
169         update_parameter(WRAP_S);
170 }
171
172 void Sampler::set_wrap_t(TextureWrap w)
173 {
174         wrap_t = w;
175         update_parameter(WRAP_T);
176 }
177
178 void Sampler::set_wrap_r(TextureWrap w)
179 {
180         static Require _req(EXT_texture3D);
181         wrap_r = w;
182         update_parameter(WRAP_R);
183 }
184
185 void Sampler::set_border_color(const Color &c)
186 {
187         border_color = c;
188         update_parameter(BORDER_COLOR);
189 }
190
191 void Sampler::disable_compare()
192 {
193         compare = false;
194         update_parameter(COMPARE);
195 }
196
197 void Sampler::set_compare(Predicate f)
198 {
199         static Require _req(ARB_shadow);
200         compare = true;
201         cmp_func = f;
202         update_parameter(COMPARE);
203 }
204
205 void Sampler::bind_to(unsigned i) const
206 {
207         TexUnit &unit = TexUnit::get_unit(i);
208         if(owner && owner!=unit.get_texture())
209                 throw invalid_operation("Sampler::bind_to");
210
211         const Sampler *cur = unit.get_sampler();
212         if(unit.set_sampler(this))
213         {
214                 if(!owner || (cur && cur->id))
215                         glBindSampler(i, id);
216
217                 if(dirty_params)
218                 {
219                         update_parameter(dirty_params);
220                         dirty_params = 0;
221                 }
222         }
223 }
224
225 const Sampler *Sampler::current(unsigned i)
226 {
227         return TexUnit::get_unit(i).get_sampler();
228 }
229
230 void Sampler::unbind_from(unsigned i)
231 {
232         TexUnit &unit = TexUnit::get_unit(i);
233         const Sampler *cur = unit.get_sampler();
234         if(unit.set_sampler(0) && cur->id)
235                 glBindSampler(i, 0);
236 }
237
238 void Sampler::unload()
239 {
240         if(owner && !owner->get_id())
241         {
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;
248                 if(wrap_s!=REPEAT)
249                         dirty_params |= WRAP_S;
250                 if(wrap_t!=REPEAT)
251                         dirty_params |= WRAP_T;
252                 if(wrap_r!=REPEAT)
253                         dirty_params |= WRAP_R;
254                 if(compare || cmp_func!=LEQUAL)
255                         dirty_params |= COMPARE;
256         }
257 }
258
259 void Sampler::set_debug_name(const string &name)
260 {
261 #ifdef DEBUG
262         if(id && KHR_debug)
263                 glObjectLabel(GL_SAMPLER, id, name.size(), name.c_str());
264 #else
265         (void)name;
266 #endif
267 }
268
269
270 Sampler::Loader::Loader(Sampler &s):
271         DataFile::ObjectLoader<Sampler>(s)
272 {
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);
283 }
284
285 void Sampler::Loader::border_color(float r, float g, float b, float a)
286 {
287         obj.set_border_color(Color(r, g, b, a));
288 }
289
290 void Sampler::Loader::compare(Predicate c)
291 {
292         obj.set_compare(c);
293 }
294
295 void Sampler::Loader::filter(TextureFilter f)
296 {
297         obj.set_filter(f);
298 }
299
300 void Sampler::Loader::mag_filter(TextureFilter f)
301 {
302         obj.set_mag_filter(f);
303 }
304
305 void Sampler::Loader::max_anisotropy(float a)
306 {
307         obj.set_max_anisotropy(a);
308 }
309
310 void Sampler::Loader::min_filter(TextureFilter f)
311 {
312         obj.set_min_filter(f);
313 }
314
315 void Sampler::Loader::wrap(TextureWrap w)
316 {
317         obj.set_wrap(w);
318 }
319
320 void Sampler::Loader::wrap_r(TextureWrap w)
321 {
322         obj.set_wrap_r(w);
323 }
324
325 void Sampler::Loader::wrap_s(TextureWrap w)
326 {
327         obj.set_wrap_s(w);
328 }
329
330 void Sampler::Loader::wrap_t(TextureWrap w)
331 {
332         obj.set_wrap_t(w);
333 }
334
335
336 bool is_mipmapped(TextureFilter filter)
337 {
338         return (filter==NEAREST_MIPMAP_NEAREST || filter==NEAREST_MIPMAP_LINEAR ||
339                 filter==LINEAR_MIPMAP_NEAREST || filter==LINEAR_MIPMAP_LINEAR);
340 }
341
342 void operator>>(const LexicalConverter &c, TextureFilter &tf)
343 {
344         if(c.get()=="NEAREST")
345                 tf = NEAREST;
346         else if(c.get()=="LINEAR")
347                 tf = 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;
356         else
357                 throw lexical_error(format("conversion of '%s' to TextureFilter", c.get()));
358 }
359
360 void operator>>(const LexicalConverter &c, TextureWrap &tw)
361 {
362         if(c.get()=="REPEAT")
363                 tw = REPEAT;
364         else if(c.get()=="CLAMP_TO_EDGE")
365                 tw = 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;
370         else
371                 throw lexical_error(format("conversion of '%s' to TextureWrap", c.get()));
372 }
373
374
375 } // namespace GL
376 } // namespace Msp