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