]> git.tdb.fi Git - libs/gl.git/blob - source/texture.cpp
Run a tighter ship with extensions
[libs/gl.git] / source / texture.cpp
1 #include <msp/gl/extensions/arb_shadow.h>
2 #include <msp/gl/extensions/ext_texture3d.h>
3 #include <msp/gl/extensions/ext_texture_filter_anisotropic.h>
4 #include <msp/gl/extensions/sgis_generate_mipmap.h>
5 #include <msp/strings/format.h>
6 #include "error.h"
7 #include "resourcemanager.h"
8 #include "resources.h"
9 #include "texture.h"
10 #include "texunit.h"
11
12 using namespace std;
13
14 namespace Msp {
15 namespace GL {
16
17 void operator>>(const LexicalConverter &c, TextureFilter &tf)
18 {
19         if(c.get()=="NEAREST")
20                 tf = NEAREST;
21         else if(c.get()=="LINEAR")
22                 tf = LINEAR;
23         else if(c.get()=="NEAREST_MIPMAP_NEAREST")
24                 tf = NEAREST_MIPMAP_NEAREST;
25         else if(c.get()=="NEAREST_MIPMAP_LINEAR")
26                 tf = NEAREST_MIPMAP_LINEAR;
27         else if(c.get()=="LINEAR_MIPMAP_NEAREST")
28                 tf = LINEAR_MIPMAP_NEAREST;
29         else if(c.get()=="LINEAR_MIPMAP_LINEAR")
30                 tf = LINEAR_MIPMAP_LINEAR;
31         else
32                 throw lexical_error(format("conversion of '%s' to TextureFilter", c.get()));
33 }
34
35
36 void operator>>(const LexicalConverter &c, TextureWrap &tw)
37 {
38         if(c.get()=="REPEAT")
39                 tw = REPEAT;
40         else if(c.get()=="CLAMP_TO_EDGE")
41                 tw = CLAMP_TO_EDGE;
42         else if(c.get()=="MIRRORED_REPEAT")
43                 tw = MIRRORED_REPEAT;
44         else
45                 throw lexical_error(format("conversion of '%s' to TextureWrap", c.get()));
46 }
47
48
49 Texture::Texture(GLenum t, ResourceManager *m):
50         id(0),
51         target(t),
52         min_filter(NEAREST_MIPMAP_LINEAR),
53         mag_filter(LINEAR),
54         wrap_s(REPEAT),
55         wrap_t(REPEAT),
56         wrap_r(REPEAT),
57         gen_mipmap(false),
58         compare(false),
59         cmp_func(LEQUAL),
60         dirty_params(0)
61 {
62         if(m)
63                 set_manager(m);
64         else
65                 glGenTextures(1, &id);
66 }
67
68 Texture::~Texture()
69 {
70         while(TexUnit *unit = TexUnit::find_unit(this))
71                 unbind_from(unit->get_index());
72
73         if(id)
74                 glDeleteTextures(1, &id);
75 }
76
77 void Texture::update_parameter(int mask) const
78 {
79         if(TexUnit::current().get_texture()!=this)
80         {
81                 TexUnit *unit = TexUnit::find_unit(this);
82                 if(!unit)
83                 {
84                         dirty_params |= mask;
85                         return;
86                 }
87
88                 unit->bind();
89         }
90
91         if(mask&MIN_FILTER)
92                 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, min_filter);
93         if(mask&MAG_FILTER)
94                 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, mag_filter);
95         if(mask&MAX_ANISOTROPY)
96                 glTexParameteri(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, max_anisotropy);
97         if(mask&WRAP_S)
98                 glTexParameteri(target, GL_TEXTURE_WRAP_S, wrap_s);
99         if(mask&WRAP_T)
100                 glTexParameteri(target, GL_TEXTURE_WRAP_T, wrap_t);
101         if(mask&WRAP_R)
102                 glTexParameteri(target, GL_TEXTURE_WRAP_R, wrap_r);
103         if(mask&GENERATE_MIPMAP)
104                 glTexParameteri(target, GL_GENERATE_MIPMAP, gen_mipmap);
105         if(mask&COMPARE)
106                 glTexParameteri(target, GL_TEXTURE_COMPARE_MODE, (compare ? GL_COMPARE_R_TO_TEXTURE : GL_NONE));
107         if(mask&COMPARE_FUNC)
108                 glTexParameteri(target, GL_TEXTURE_COMPARE_FUNC, cmp_func);
109 }
110
111 void Texture::set_min_filter(TextureFilter f)
112 {
113         min_filter = f;
114         update_parameter(MIN_FILTER);
115 }
116
117 void Texture::set_mag_filter(TextureFilter f)
118 {
119         mag_filter = f;
120         update_parameter(MAG_FILTER);
121 }
122
123 void Texture::set_filter(TextureFilter f)
124 {
125         set_min_filter(f);
126         set_mag_filter(f==NEAREST ? NEAREST : LINEAR);
127 }
128
129 void Texture::set_max_anisotropy(float a)
130 {
131         if(a<1.0f)
132                 throw invalid_argument("Texture::set_max_anisotropy");
133         else if(a>1.0f)
134                 static Require _req(EXT_texture_filter_anisotropic);
135         max_anisotropy = a;
136         update_parameter(MAX_ANISOTROPY);
137 }
138
139 void Texture::set_wrap(TextureWrap w)
140 {
141         set_wrap_s(w);
142         set_wrap_t(w);
143         if(EXT_texture3D)
144                 set_wrap_r(w);
145 }
146
147 void Texture::set_wrap_s(TextureWrap w)
148 {
149         wrap_s = w;
150         update_parameter(WRAP_S);
151 }
152
153 void Texture::set_wrap_t(TextureWrap w)
154 {
155         wrap_t = w;
156         update_parameter(WRAP_T);
157 }
158
159 void Texture::set_wrap_r(TextureWrap w)
160 {
161         static Require _req(EXT_texture3D);
162         wrap_r = w;
163         update_parameter(WRAP_R);
164 }
165
166 void Texture::set_generate_mipmap(bool gm)
167 {
168         if(gm)
169                 static Require _req(SGIS_generate_mipmap);
170         gen_mipmap = gm;
171         update_parameter(GENERATE_MIPMAP);
172 }
173
174 void Texture::set_compare_enabled(bool c)
175 {
176         static Require _req(ARB_shadow);
177         compare = c;
178         update_parameter(COMPARE);
179 }
180
181 void Texture::set_compare_func(Predicate f)
182 {
183         static Require _req(ARB_shadow);
184         cmp_func = f;
185         update_parameter(COMPARE_FUNC);
186 }
187
188 void Texture::bind_to(unsigned i) const
189 {
190         if(!id)
191         {
192                 if(manager)
193                         manager->resource_used(*this);
194                 if(!id)
195                 {
196                         unbind_from(i);
197                         return;
198                 }
199         }
200
201         TexUnit &unit = TexUnit::get_unit(i);
202         const Texture *cur = unit.get_texture();
203         if(unit.set_texture(this))
204         {
205                 if(manager)
206                         manager->resource_used(*this);
207
208                 unit.bind();
209                 if(cur && cur->target!=target)
210                         glDisable(cur->target);
211                 if(!cur || cur->target!=target)
212                         glEnable(target);
213                 glBindTexture(target, id);
214
215                 if(dirty_params)
216                 {
217                         update_parameter(dirty_params);
218                         dirty_params = 0;
219                 }
220         }
221 }
222
223 const Texture *Texture::current(unsigned i)
224 {
225         return TexUnit::get_unit(i).get_texture();
226 }
227
228 void Texture::unbind_from(unsigned i)
229 {
230         TexUnit &unit = TexUnit::get_unit(i);
231         const Texture *cur = unit.get_texture();
232         if(unit.set_texture(0))
233         {
234                 unit.bind();
235                 glBindTexture(cur->target, 0);
236                 glDisable(cur->target);
237         }
238 }
239
240
241 Texture::Loader::Loader(Texture &t):
242         DataFile::CollectionObjectLoader<Texture>(t, 0)
243 {
244         init();
245 }
246
247 Texture::Loader::Loader(Texture &t, Collection &c):
248         DataFile::CollectionObjectLoader<Texture>(t, &c)
249 {
250         init();
251 }
252
253 void Texture::Loader::init()
254 {
255         if(Resources *res = dynamic_cast<Resources *>(coll))
256                 srgb = res->get_srgb_conversion();
257         else
258                 srgb = false;
259
260         add("filter", &Loader::filter);
261         add("max_anisotropy", &Loader::max_anisotropy);
262         add("generate_mipmap", &Loader::generate_mipmap);
263         add("mag_filter", &Loader::mag_filter);
264         add("min_filter", &Loader::min_filter);
265         add("wrap",       &Loader::wrap);
266         add("wrap_r",     &Loader::wrap_r);
267         add("wrap_s",     &Loader::wrap_s);
268         add("wrap_t",     &Loader::wrap_t);
269 }
270
271 void Texture::Loader::filter(TextureFilter f)
272 {
273         obj.set_filter(f);
274 }
275
276 void Texture::Loader::generate_mipmap(bool gm)
277 {
278         obj.set_generate_mipmap(gm);
279 }
280
281 void Texture::Loader::mag_filter(TextureFilter f)
282 {
283         obj.set_mag_filter(f);
284 }
285
286 void Texture::Loader::max_anisotropy(float a)
287 {
288         obj.set_max_anisotropy(a);
289 }
290
291 void Texture::Loader::min_filter(TextureFilter f)
292 {
293         obj.set_min_filter(f);
294 }
295
296 void Texture::Loader::wrap(TextureWrap w)
297 {
298         obj.set_wrap(w);
299 }
300
301 void Texture::Loader::wrap_r(TextureWrap w)
302 {
303         obj.set_wrap_r(w);
304 }
305
306 void Texture::Loader::wrap_s(TextureWrap w)
307 {
308         obj.set_wrap_s(w);
309 }
310
311 void Texture::Loader::wrap_t(TextureWrap w)
312 {
313         obj.set_wrap_t(w);
314 }
315
316 } // namespace GL
317 } // namespace Msp