]> git.tdb.fi Git - libs/gl.git/blob - source/sampler.cpp
Remove the deprecated ProgramBuilder class
[libs/gl.git] / source / 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         compare = false;
48         cmp_func = LEQUAL;
49         dirty_params = 0;
50 }
51
52 void Sampler::update_parameter(int mask) const
53 {
54         if(owner)
55         {
56                 if(!owner->get_id())
57                 {
58                         dirty_params |= mask;
59                         return;
60                 }
61
62                 if(!ARB_direct_state_access && TexUnit::current().get_texture()!=owner)
63                 {
64                         TexUnit *unit = TexUnit::find_unit(owner);
65                         if(!unit)
66                         {
67                                 dirty_params |= mask;
68                                 return;
69                         }
70
71                         unit->bind();
72                 }
73         }
74
75         if(mask&MIN_FILTER)
76                 set_parameter_i(GL_TEXTURE_MIN_FILTER, min_filter);
77         if(mask&MAG_FILTER)
78                 set_parameter_i(GL_TEXTURE_MAG_FILTER, mag_filter);
79         if(mask&MAX_ANISOTROPY)
80                 set_parameter_f(GL_TEXTURE_MAX_ANISOTROPY_EXT, max_anisotropy);
81         if(mask&WRAP_S)
82                 set_parameter_i(GL_TEXTURE_WRAP_S, wrap_s);
83         if(mask&WRAP_T)
84                 set_parameter_i(GL_TEXTURE_WRAP_T, wrap_t);
85         if(mask&WRAP_R)
86                 set_parameter_i(GL_TEXTURE_WRAP_R, wrap_r);
87         if(mask&COMPARE)
88         {
89                 set_parameter_i(GL_TEXTURE_COMPARE_MODE, (compare ? GL_COMPARE_R_TO_TEXTURE : GL_NONE));
90                 if(compare)
91                         set_parameter_i(GL_TEXTURE_COMPARE_FUNC, cmp_func);
92         }
93 }
94
95 void Sampler::set_parameter_i(unsigned param, int value) const
96 {
97         if(id)
98                 glSamplerParameteri(id, param, value);
99         else if(ARB_direct_state_access)
100                 glTextureParameteri(owner->get_id(), param, value);
101         else
102                 glTexParameteri(owner->get_target(), param, value);
103 }
104
105 void Sampler::set_parameter_f(unsigned param, float value) const
106 {
107         if(id)
108                 glSamplerParameterf(id, param, value);
109         else if(ARB_direct_state_access)
110                 glTextureParameterf(owner->get_id(), param, value);
111         else
112                 glTexParameterf(owner->get_target(), param, value);
113 }
114
115 void Sampler::set_min_filter(TextureFilter f)
116 {
117         min_filter = f;
118         update_parameter(MIN_FILTER);
119 }
120
121 void Sampler::set_mag_filter(TextureFilter f)
122 {
123         mag_filter = f;
124         update_parameter(MAG_FILTER);
125 }
126
127 void Sampler::set_filter(TextureFilter f)
128 {
129         set_min_filter(f);
130         set_mag_filter(f==NEAREST ? NEAREST : LINEAR);
131 }
132
133 void Sampler::set_max_anisotropy(float a)
134 {
135         if(a<1.0f)
136                 throw invalid_argument("Sampler::set_max_anisotropy");
137         else if(a>1.0f)
138                 static Require _req(EXT_texture_filter_anisotropic);
139         max_anisotropy = a;
140         if(EXT_texture_filter_anisotropic)
141                 update_parameter(MAX_ANISOTROPY);
142 }
143
144 void Sampler::set_wrap(TextureWrap w)
145 {
146         set_wrap_s(w);
147         set_wrap_t(w);
148         if(EXT_texture3D)
149                 set_wrap_r(w);
150 }
151
152 void Sampler::set_wrap_s(TextureWrap w)
153 {
154         wrap_s = w;
155         update_parameter(WRAP_S);
156 }
157
158 void Sampler::set_wrap_t(TextureWrap w)
159 {
160         wrap_t = w;
161         update_parameter(WRAP_T);
162 }
163
164 void Sampler::set_wrap_r(TextureWrap w)
165 {
166         static Require _req(EXT_texture3D);
167         wrap_r = w;
168         update_parameter(WRAP_R);
169 }
170
171 void Sampler::disable_compare()
172 {
173         compare = false;
174         update_parameter(COMPARE);
175 }
176
177 void Sampler::set_compare(Predicate f)
178 {
179         static Require _req(ARB_shadow);
180         compare = true;
181         cmp_func = f;
182         update_parameter(COMPARE);
183 }
184
185 void Sampler::bind_to(unsigned i) const
186 {
187         TexUnit &unit = TexUnit::get_unit(i);
188         if(owner && owner!=unit.get_texture())
189                 throw invalid_operation("Sampler::bind_to");
190
191         const Sampler *cur = unit.get_sampler();
192         if(unit.set_sampler(this))
193         {
194                 if(!owner || (cur && cur->id))
195                         glBindSampler(i, id);
196
197                 if(dirty_params)
198                 {
199                         update_parameter(dirty_params);
200                         dirty_params = 0;
201                 }
202         }
203 }
204
205 const Sampler *Sampler::current(unsigned i)
206 {
207         return TexUnit::get_unit(i).get_sampler();
208 }
209
210 void Sampler::unbind_from(unsigned i)
211 {
212         TexUnit &unit = TexUnit::get_unit(i);
213         const Sampler *cur = unit.get_sampler();
214         if(unit.set_sampler(0) && cur->id)
215                 glBindSampler(i, 0);
216 }
217
218 void Sampler::unload()
219 {
220         if(owner && !owner->get_id())
221         {
222                 if(min_filter!=NEAREST_MIPMAP_LINEAR)
223                         dirty_params |= MIN_FILTER;
224                 if(mag_filter!=LINEAR)
225                         dirty_params |= MAG_FILTER;
226                 if(max_anisotropy!=1.0f)
227                         dirty_params |= MAX_ANISOTROPY;
228                 if(wrap_s!=REPEAT)
229                         dirty_params |= WRAP_S;
230                 if(wrap_t!=REPEAT)
231                         dirty_params |= WRAP_T;
232                 if(wrap_r!=REPEAT)
233                         dirty_params |= WRAP_R;
234                 if(compare || cmp_func!=LEQUAL)
235                         dirty_params |= COMPARE;
236         }
237 }
238
239
240 Sampler::Loader::Loader(Sampler &s):
241         DataFile::ObjectLoader<Sampler>(s)
242 {
243         add("filter", &Loader::filter);
244         add("mag_filter", &Loader::mag_filter);
245         add("max_anisotropy", &Loader::max_anisotropy);
246         add("min_filter", &Loader::min_filter);
247         add("wrap", &Loader::wrap);
248         add("wrap_r", &Loader::wrap_r);
249         add("wrap_s", &Loader::wrap_s);
250         add("wrap_t", &Loader::wrap_t);
251 }
252
253 void Sampler::Loader::filter(TextureFilter f)
254 {
255         obj.set_filter(f);
256 }
257
258 void Sampler::Loader::mag_filter(TextureFilter f)
259 {
260         obj.set_mag_filter(f);
261 }
262
263 void Sampler::Loader::max_anisotropy(float a)
264 {
265         obj.set_max_anisotropy(a);
266 }
267
268 void Sampler::Loader::min_filter(TextureFilter f)
269 {
270         obj.set_min_filter(f);
271 }
272
273 void Sampler::Loader::wrap(TextureWrap w)
274 {
275         obj.set_wrap(w);
276 }
277
278 void Sampler::Loader::wrap_r(TextureWrap w)
279 {
280         obj.set_wrap_r(w);
281 }
282
283 void Sampler::Loader::wrap_s(TextureWrap w)
284 {
285         obj.set_wrap_s(w);
286 }
287
288 void Sampler::Loader::wrap_t(TextureWrap w)
289 {
290         obj.set_wrap_t(w);
291 }
292
293
294 bool is_mipmapped(TextureFilter filter)
295 {
296         return (filter==NEAREST_MIPMAP_NEAREST || filter==NEAREST_MIPMAP_LINEAR ||
297                 filter==LINEAR_MIPMAP_NEAREST || filter==LINEAR_MIPMAP_LINEAR);
298 }
299
300 void operator>>(const LexicalConverter &c, TextureFilter &tf)
301 {
302         if(c.get()=="NEAREST")
303                 tf = NEAREST;
304         else if(c.get()=="LINEAR")
305                 tf = LINEAR;
306         else if(c.get()=="NEAREST_MIPMAP_NEAREST")
307                 tf = NEAREST_MIPMAP_NEAREST;
308         else if(c.get()=="NEAREST_MIPMAP_LINEAR")
309                 tf = NEAREST_MIPMAP_LINEAR;
310         else if(c.get()=="LINEAR_MIPMAP_NEAREST")
311                 tf = LINEAR_MIPMAP_NEAREST;
312         else if(c.get()=="LINEAR_MIPMAP_LINEAR")
313                 tf = LINEAR_MIPMAP_LINEAR;
314         else
315                 throw lexical_error(format("conversion of '%s' to TextureFilter", c.get()));
316 }
317
318 void operator>>(const LexicalConverter &c, TextureWrap &tw)
319 {
320         if(c.get()=="REPEAT")
321                 tw = REPEAT;
322         else if(c.get()=="CLAMP_TO_EDGE")
323                 tw = CLAMP_TO_EDGE;
324         else if(c.get()=="MIRRORED_REPEAT")
325                 tw = MIRRORED_REPEAT;
326         else
327                 throw lexical_error(format("conversion of '%s' to TextureWrap", c.get()));
328 }
329
330
331 } // namespace GL
332 } // namespace Msp