]> git.tdb.fi Git - libs/gl.git/blob - source/sampler.cpp
Move texture sampler state to a separate object
[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(const Texture &tex):
18         id(0),
19         owner(&tex)
20 {
21         if(this!=&tex.get_default_sampler())
22                 throw invalid_argument("Sampler::Sampler");
23
24         init();
25 }
26
27 void Sampler::init()
28 {
29         min_filter = NEAREST_MIPMAP_LINEAR;
30         mag_filter = LINEAR;
31         max_anisotropy = 1.0f;
32         wrap_s = REPEAT;
33         wrap_t = REPEAT;
34         wrap_r = REPEAT;
35         compare = false;
36         cmp_func = LEQUAL;
37         dirty_params = 0;
38 }
39
40 void Sampler::update_parameter(int mask) const
41 {
42         if(!owner->get_id() || (!ARB_direct_state_access && TexUnit::current().get_texture()!=owner))
43         {
44                 TexUnit *unit = TexUnit::find_unit(owner);
45                 if(!unit)
46                 {
47                         dirty_params |= mask;
48                         return;
49                 }
50
51                 unit->bind();
52         }
53
54         if(mask&MIN_FILTER)
55                 set_parameter_i(GL_TEXTURE_MIN_FILTER, min_filter);
56         if(mask&MAG_FILTER)
57                 set_parameter_i(GL_TEXTURE_MAG_FILTER, mag_filter);
58         if(mask&MAX_ANISOTROPY)
59                 set_parameter_f(GL_TEXTURE_MAX_ANISOTROPY_EXT, max_anisotropy);
60         if(mask&WRAP_S)
61                 set_parameter_i(GL_TEXTURE_WRAP_S, wrap_s);
62         if(mask&WRAP_T)
63                 set_parameter_i(GL_TEXTURE_WRAP_T, wrap_t);
64         if(mask&WRAP_R)
65                 set_parameter_i(GL_TEXTURE_WRAP_R, wrap_r);
66         if(mask&COMPARE)
67         {
68                 set_parameter_i(GL_TEXTURE_COMPARE_MODE, (compare ? GL_COMPARE_R_TO_TEXTURE : GL_NONE));
69                 if(compare)
70                         set_parameter_i(GL_TEXTURE_COMPARE_FUNC, cmp_func);
71         }
72 }
73
74 void Sampler::set_parameter_i(unsigned param, int value) const
75 {
76         if(ARB_direct_state_access)
77                 glTextureParameteri(owner->get_id(), param, value);
78         else
79                 glTexParameteri(owner->get_target(), param, value);
80 }
81
82 void Sampler::set_parameter_f(unsigned param, float value) const
83 {
84         if(ARB_direct_state_access)
85                 glTextureParameterf(owner->get_id(), param, value);
86         else
87                 glTexParameterf(owner->get_target(), param, value);
88 }
89
90 void Sampler::set_min_filter(TextureFilter f)
91 {
92         min_filter = f;
93         update_parameter(MIN_FILTER);
94 }
95
96 void Sampler::set_mag_filter(TextureFilter f)
97 {
98         mag_filter = f;
99         update_parameter(MAG_FILTER);
100 }
101
102 void Sampler::set_filter(TextureFilter f)
103 {
104         set_min_filter(f);
105         set_mag_filter(f==NEAREST ? NEAREST : LINEAR);
106 }
107
108 void Sampler::set_max_anisotropy(float a)
109 {
110         if(a<1.0f)
111                 throw invalid_argument("Sampler::set_max_anisotropy");
112         else if(a>1.0f)
113                 static Require _req(EXT_texture_filter_anisotropic);
114         max_anisotropy = a;
115         if(EXT_texture_filter_anisotropic)
116                 update_parameter(MAX_ANISOTROPY);
117 }
118
119 void Sampler::set_wrap(TextureWrap w)
120 {
121         set_wrap_s(w);
122         set_wrap_t(w);
123         if(EXT_texture3D)
124                 set_wrap_r(w);
125 }
126
127 void Sampler::set_wrap_s(TextureWrap w)
128 {
129         wrap_s = w;
130         update_parameter(WRAP_S);
131 }
132
133 void Sampler::set_wrap_t(TextureWrap w)
134 {
135         wrap_t = w;
136         update_parameter(WRAP_T);
137 }
138
139 void Sampler::set_wrap_r(TextureWrap w)
140 {
141         static Require _req(EXT_texture3D);
142         wrap_r = w;
143         update_parameter(WRAP_R);
144 }
145
146 void Sampler::disable_compare()
147 {
148         compare = false;
149         update_parameter(COMPARE);
150 }
151
152 void Sampler::set_compare(Predicate f)
153 {
154         static Require _req(ARB_shadow);
155         compare = true;
156         cmp_func = f;
157         update_parameter(COMPARE);
158 }
159
160 void Sampler::bind_to(unsigned i) const
161 {
162         TexUnit &unit = TexUnit::get_unit(i);
163         if(owner!=unit.get_texture())
164                 throw invalid_operation("Sampler::bind_to");
165
166         if(dirty_params)
167         {
168                 update_parameter(dirty_params);
169                 dirty_params = 0;
170         }
171 }
172
173 void Sampler::unload()
174 {
175         // TODO check which params actually need refreshing
176         if(!owner->get_id())
177                 dirty_params = -1;
178 }
179
180
181 Sampler::Loader::Loader(Sampler &s):
182         DataFile::ObjectLoader<Sampler>(s)
183 {
184         add("filter", &Loader::filter);
185         add("mag_filter", &Loader::mag_filter);
186         add("max_anisotropy", &Loader::max_anisotropy);
187         add("min_filter", &Loader::min_filter);
188         add("wrap", &Loader::wrap);
189         add("wrap_r", &Loader::wrap_r);
190         add("wrap_s", &Loader::wrap_s);
191         add("wrap_t", &Loader::wrap_t);
192 }
193
194 void Sampler::Loader::filter(TextureFilter f)
195 {
196         obj.set_filter(f);
197 }
198
199 void Sampler::Loader::mag_filter(TextureFilter f)
200 {
201         obj.set_mag_filter(f);
202 }
203
204 void Sampler::Loader::max_anisotropy(float a)
205 {
206         obj.set_max_anisotropy(a);
207 }
208
209 void Sampler::Loader::min_filter(TextureFilter f)
210 {
211         obj.set_min_filter(f);
212 }
213
214 void Sampler::Loader::wrap(TextureWrap w)
215 {
216         obj.set_wrap(w);
217 }
218
219 void Sampler::Loader::wrap_r(TextureWrap w)
220 {
221         obj.set_wrap_r(w);
222 }
223
224 void Sampler::Loader::wrap_s(TextureWrap w)
225 {
226         obj.set_wrap_s(w);
227 }
228
229 void Sampler::Loader::wrap_t(TextureWrap w)
230 {
231         obj.set_wrap_t(w);
232 }
233
234
235 bool is_mipmapped(TextureFilter filter)
236 {
237         return (filter==NEAREST_MIPMAP_NEAREST || filter==NEAREST_MIPMAP_LINEAR ||
238                 filter==LINEAR_MIPMAP_NEAREST || filter==LINEAR_MIPMAP_LINEAR);
239 }
240
241 void operator>>(const LexicalConverter &c, TextureFilter &tf)
242 {
243         if(c.get()=="NEAREST")
244                 tf = NEAREST;
245         else if(c.get()=="LINEAR")
246                 tf = LINEAR;
247         else if(c.get()=="NEAREST_MIPMAP_NEAREST")
248                 tf = NEAREST_MIPMAP_NEAREST;
249         else if(c.get()=="NEAREST_MIPMAP_LINEAR")
250                 tf = NEAREST_MIPMAP_LINEAR;
251         else if(c.get()=="LINEAR_MIPMAP_NEAREST")
252                 tf = LINEAR_MIPMAP_NEAREST;
253         else if(c.get()=="LINEAR_MIPMAP_LINEAR")
254                 tf = LINEAR_MIPMAP_LINEAR;
255         else
256                 throw lexical_error(format("conversion of '%s' to TextureFilter", c.get()));
257 }
258
259 void operator>>(const LexicalConverter &c, TextureWrap &tw)
260 {
261         if(c.get()=="REPEAT")
262                 tw = REPEAT;
263         else if(c.get()=="CLAMP_TO_EDGE")
264                 tw = CLAMP_TO_EDGE;
265         else if(c.get()=="MIRRORED_REPEAT")
266                 tw = MIRRORED_REPEAT;
267         else
268                 throw lexical_error(format("conversion of '%s' to TextureWrap", c.get()));
269 }
270
271
272 } // namespace GL
273 } // namespace Msp