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