]> git.tdb.fi Git - libs/gl.git/blob - source/sampler.cpp
Support samplers as independent objects
[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         // TODO check which params actually need refreshing
221         if(!owner->get_id())
222                 dirty_params = -1;
223 }
224
225
226 Sampler::Loader::Loader(Sampler &s):
227         DataFile::ObjectLoader<Sampler>(s)
228 {
229         add("filter", &Loader::filter);
230         add("mag_filter", &Loader::mag_filter);
231         add("max_anisotropy", &Loader::max_anisotropy);
232         add("min_filter", &Loader::min_filter);
233         add("wrap", &Loader::wrap);
234         add("wrap_r", &Loader::wrap_r);
235         add("wrap_s", &Loader::wrap_s);
236         add("wrap_t", &Loader::wrap_t);
237 }
238
239 void Sampler::Loader::filter(TextureFilter f)
240 {
241         obj.set_filter(f);
242 }
243
244 void Sampler::Loader::mag_filter(TextureFilter f)
245 {
246         obj.set_mag_filter(f);
247 }
248
249 void Sampler::Loader::max_anisotropy(float a)
250 {
251         obj.set_max_anisotropy(a);
252 }
253
254 void Sampler::Loader::min_filter(TextureFilter f)
255 {
256         obj.set_min_filter(f);
257 }
258
259 void Sampler::Loader::wrap(TextureWrap w)
260 {
261         obj.set_wrap(w);
262 }
263
264 void Sampler::Loader::wrap_r(TextureWrap w)
265 {
266         obj.set_wrap_r(w);
267 }
268
269 void Sampler::Loader::wrap_s(TextureWrap w)
270 {
271         obj.set_wrap_s(w);
272 }
273
274 void Sampler::Loader::wrap_t(TextureWrap w)
275 {
276         obj.set_wrap_t(w);
277 }
278
279
280 bool is_mipmapped(TextureFilter filter)
281 {
282         return (filter==NEAREST_MIPMAP_NEAREST || filter==NEAREST_MIPMAP_LINEAR ||
283                 filter==LINEAR_MIPMAP_NEAREST || filter==LINEAR_MIPMAP_LINEAR);
284 }
285
286 void operator>>(const LexicalConverter &c, TextureFilter &tf)
287 {
288         if(c.get()=="NEAREST")
289                 tf = NEAREST;
290         else if(c.get()=="LINEAR")
291                 tf = LINEAR;
292         else if(c.get()=="NEAREST_MIPMAP_NEAREST")
293                 tf = NEAREST_MIPMAP_NEAREST;
294         else if(c.get()=="NEAREST_MIPMAP_LINEAR")
295                 tf = NEAREST_MIPMAP_LINEAR;
296         else if(c.get()=="LINEAR_MIPMAP_NEAREST")
297                 tf = LINEAR_MIPMAP_NEAREST;
298         else if(c.get()=="LINEAR_MIPMAP_LINEAR")
299                 tf = LINEAR_MIPMAP_LINEAR;
300         else
301                 throw lexical_error(format("conversion of '%s' to TextureFilter", c.get()));
302 }
303
304 void operator>>(const LexicalConverter &c, TextureWrap &tw)
305 {
306         if(c.get()=="REPEAT")
307                 tw = REPEAT;
308         else if(c.get()=="CLAMP_TO_EDGE")
309                 tw = CLAMP_TO_EDGE;
310         else if(c.get()=="MIRRORED_REPEAT")
311                 tw = MIRRORED_REPEAT;
312         else
313                 throw lexical_error(format("conversion of '%s' to TextureWrap", c.get()));
314 }
315
316
317 } // namespace GL
318 } // namespace Msp