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