]> git.tdb.fi Git - libs/gl.git/blob - source/texture.cpp
Remove separate element_buffer from Renderer, get it from mesh instead
[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 *old = unit.get_texture();
203         if(unit.set_texture(this))
204         {
205                 if(manager)
206                         manager->resource_used(*this);
207
208                 unit.bind();
209                 if(unit.supports_legacy())
210                 {
211                         if(old && old->target!=target)
212                                 glDisable(old->target);
213                         if(!old || old->target!=target)
214                                 glEnable(target);
215                 }
216                 glBindTexture(target, id);
217
218                 if(dirty_params)
219                 {
220                         update_parameter(dirty_params);
221                         dirty_params = 0;
222                 }
223         }
224 }
225
226 const Texture *Texture::current(unsigned i)
227 {
228         return TexUnit::get_unit(i).get_texture();
229 }
230
231 void Texture::unbind_from(unsigned i)
232 {
233         TexUnit &unit = TexUnit::get_unit(i);
234         const Texture *cur = unit.get_texture();
235         if(unit.set_texture(0))
236         {
237                 unit.bind();
238                 glBindTexture(cur->target, 0);
239                 if(unit.supports_legacy())
240                         glDisable(cur->target);
241         }
242 }
243
244
245 Texture::Loader::Loader(Texture &t):
246         DataFile::CollectionObjectLoader<Texture>(t, 0)
247 {
248         init();
249 }
250
251 Texture::Loader::Loader(Texture &t, Collection &c):
252         DataFile::CollectionObjectLoader<Texture>(t, &c)
253 {
254         init();
255 }
256
257 void Texture::Loader::init()
258 {
259         if(Resources *res = dynamic_cast<Resources *>(coll))
260                 srgb = res->get_srgb_conversion();
261         else
262                 srgb = false;
263
264         add("filter", &Loader::filter);
265         add("max_anisotropy", &Loader::max_anisotropy);
266         add("generate_mipmap", &Loader::generate_mipmap);
267         add("mag_filter", &Loader::mag_filter);
268         add("min_filter", &Loader::min_filter);
269         add("wrap",       &Loader::wrap);
270         add("wrap_r",     &Loader::wrap_r);
271         add("wrap_s",     &Loader::wrap_s);
272         add("wrap_t",     &Loader::wrap_t);
273 }
274
275 void Texture::Loader::filter(TextureFilter f)
276 {
277         obj.set_filter(f);
278 }
279
280 void Texture::Loader::generate_mipmap(bool gm)
281 {
282         obj.set_generate_mipmap(gm);
283 }
284
285 void Texture::Loader::mag_filter(TextureFilter f)
286 {
287         obj.set_mag_filter(f);
288 }
289
290 void Texture::Loader::max_anisotropy(float a)
291 {
292         obj.set_max_anisotropy(a);
293 }
294
295 void Texture::Loader::min_filter(TextureFilter f)
296 {
297         obj.set_min_filter(f);
298 }
299
300 void Texture::Loader::wrap(TextureWrap w)
301 {
302         obj.set_wrap(w);
303 }
304
305 void Texture::Loader::wrap_r(TextureWrap w)
306 {
307         obj.set_wrap_r(w);
308 }
309
310 void Texture::Loader::wrap_s(TextureWrap w)
311 {
312         obj.set_wrap_s(w);
313 }
314
315 void Texture::Loader::wrap_t(TextureWrap w)
316 {
317         obj.set_wrap_t(w);
318 }
319
320 } // namespace GL
321 } // namespace Msp