]> git.tdb.fi Git - libs/gl.git/blob - source/texture.cpp
Support BGR and BGRA as texture formats through swizzling
[libs/gl.git] / source / texture.cpp
1 #include <msp/gl/extensions/arb_direct_state_access.h>
2 #include <msp/gl/extensions/arb_texture_swizzle.h>
3 #include <msp/gl/extensions/ext_framebuffer_object.h>
4 #include <msp/io/memory.h>
5 #include "bindable.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 int Texture::swizzle_orders[] =
18 {
19         GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA,
20         GL_RED, GL_RED, GL_RED, GL_ONE,
21         GL_RED, GL_RED, GL_RED, GL_GREEN,
22         GL_BLUE, GL_GREEN, GL_RED, GL_ALPHA
23 };
24
25 Texture::Texture(GLenum t, ResourceManager *m):
26         id(0),
27         target(t),
28         ifmt(RGB8),
29         swizzle(NO_SWIZZLE),
30         auto_gen_mipmap(false),
31         default_sampler(*this)
32 {
33         if(m)
34                 set_manager(m);
35         else if(ARB_direct_state_access)
36                 glCreateTextures(target, 1, &id);
37         else
38                 glGenTextures(1, &id);
39 }
40
41 Texture::~Texture()
42 {
43         while(TexUnit *unit = TexUnit::find_unit(this))
44                 unbind_from(unit->get_index());
45
46         if(id)
47                 glDeleteTextures(1, &id);
48 }
49
50 void Texture::set_internal_format(PixelFormat fmt)
51 {
52         PixelComponents comp = get_components(fmt);
53         FormatSwizzle swiz = NO_SWIZZLE;
54         switch(comp)
55         {
56         case LUMINANCE:
57                 comp = RED;
58                 swiz = R_TO_LUMINANCE;
59                 break;
60         case LUMINANCE_ALPHA:
61                 comp = RG;
62                 swiz = RG_TO_LUMINANCE_ALPHA;
63                 break;
64         case BGR:
65                 comp = RGB;
66                 swiz = RGB_TO_BGR;
67                 break;
68         case BGRA:
69                 comp = RGBA;
70                 swiz = RGB_TO_BGR;
71                 break;
72         default:;
73         }
74
75         fmt = make_pixelformat(comp, get_component_type(fmt));
76         require_pixelformat(fmt);
77         if(swiz!=NO_SWIZZLE)
78                 static Require _req(ARB_texture_swizzle);
79         ifmt = fmt;
80         swizzle = swiz;
81 }
82
83 PixelComponents Texture::get_upload_components(PixelComponents comp) const
84 {
85         if(comp==LUMINANCE || comp==LUMINANCE_ALPHA || comp==BGR || comp==BGRA)
86                 return get_components(ifmt);
87         else
88                 return comp;
89 }
90
91 void Texture::apply_swizzle()
92 {
93         if(swizzle==NO_SWIZZLE)
94                 return;
95
96         if(get_gl_api()==OPENGL_ES2)
97         {
98                 set_parameter_i(GL_TEXTURE_SWIZZLE_R, swizzle_orders[swizzle*4]);
99                 set_parameter_i(GL_TEXTURE_SWIZZLE_G, swizzle_orders[swizzle*4+1]);
100                 set_parameter_i(GL_TEXTURE_SWIZZLE_B, swizzle_orders[swizzle*4+2]);
101                 set_parameter_i(GL_TEXTURE_SWIZZLE_A, swizzle_orders[swizzle*4+3]);
102         }
103         else
104         {
105                 if(ARB_direct_state_access)
106                         glTextureParameteriv(id, GL_TEXTURE_SWIZZLE_RGBA, swizzle_orders+swizzle*4);
107                 else
108                         glTexParameteriv(target, GL_TEXTURE_SWIZZLE_RGBA, swizzle_orders+swizzle*4);
109         }
110 }
111
112 void Texture::set_parameter_i(GLenum param, int value) const
113 {
114         if(ARB_direct_state_access)
115                 glTextureParameteri(id, param, value);
116         else
117                 glTexParameteri(target, param, value);
118 }
119
120 void Texture::set_min_filter(TextureFilter f)
121 {
122         default_sampler.set_min_filter(f);
123 }
124
125 void Texture::set_mag_filter(TextureFilter f)
126 {
127         default_sampler.set_mag_filter(f);
128 }
129
130 void Texture::set_filter(TextureFilter f)
131 {
132         default_sampler.set_filter(f);
133 }
134
135 void Texture::set_max_anisotropy(float a)
136 {
137         default_sampler.set_max_anisotropy(a);
138 }
139
140 void Texture::set_wrap(TextureWrap w)
141 {
142         default_sampler.set_wrap(w);
143 }
144
145 void Texture::set_wrap_s(TextureWrap w)
146 {
147         default_sampler.set_wrap_s(w);
148 }
149
150 void Texture::set_wrap_t(TextureWrap w)
151 {
152         default_sampler.set_wrap_t(w);
153 }
154
155 void Texture::set_wrap_r(TextureWrap w)
156 {
157         default_sampler.set_wrap_r(w);
158 }
159
160 bool Texture::can_generate_mipmap()
161 {
162         return EXT_framebuffer_object;
163 }
164
165 void Texture::generate_mipmap()
166 {
167         // glGenerateMipmap is defined here
168         static Require _req(EXT_framebuffer_object);
169
170         if(ARB_direct_state_access)
171                 glGenerateTextureMipmap(id);
172         else
173         {
174                 BindRestore _bind(this);
175                 glGenerateMipmap(target);
176         }
177 }
178
179 void Texture::set_auto_generate_mipmap(bool gm)
180 {
181         if(gm)
182                 static Require _req(EXT_framebuffer_object);
183
184         auto_gen_mipmap = gm;
185 }
186
187 void Texture::set_compare_enabled(bool c)
188 {
189         if(c)
190                 default_sampler.set_compare(default_sampler.get_compare_function());
191         else
192                 default_sampler.disable_compare();
193 }
194
195 void Texture::set_compare_func(Predicate f)
196 {
197         default_sampler.set_compare(f);
198 }
199
200 void Texture::load_image(const string &fn, bool srgb)
201 {
202         load_image(fn, 0, srgb);
203 }
204
205 void Texture::load_image(const string &fn, unsigned lv, bool srgb)
206 {
207         Graphics::Image img;
208         img.load_file(fn);
209
210         image(img, lv, srgb);
211 }
212
213 void Texture::image(const Graphics::Image &img, bool srgb)
214 {
215         image(img, 0, srgb);
216 }
217
218 void Texture::bind_to(unsigned i) const
219 {
220         if(!id)
221         {
222                 if(manager)
223                         manager->resource_used(*this);
224                 if(!id)
225                 {
226                         unbind_from(i);
227                         return;
228                 }
229         }
230
231         TexUnit &unit = TexUnit::get_unit(i);
232         if(unit.set_texture(this))
233         {
234                 if(manager)
235                         manager->resource_used(*this);
236
237                 if(ARB_direct_state_access)
238                         glBindTextureUnit(i, id);
239                 else
240                 {
241                         unit.bind();
242                         glBindTexture(target, id);
243                 }
244
245                 default_sampler.bind_to(i);
246         }
247 }
248
249 const Texture *Texture::current(unsigned i)
250 {
251         return TexUnit::get_unit(i).get_texture();
252 }
253
254 void Texture::unbind_from(unsigned i)
255 {
256         TexUnit &unit = TexUnit::get_unit(i);
257         const Texture *cur = unit.get_texture();
258         if(unit.set_texture(0))
259         {
260                 if(ARB_direct_state_access)
261                         glBindTextureUnit(i, 0);
262                 else
263                 {
264                         unit.bind();
265                         glBindTexture(cur->target, 0);
266                 }
267         }
268 }
269
270
271 Texture::Loader::Loader(Texture &t):
272         DataFile::CollectionObjectLoader<Texture>(t, 0)
273 {
274         init();
275 }
276
277 Texture::Loader::Loader(Texture &t, Collection &c):
278         DataFile::CollectionObjectLoader<Texture>(t, &c)
279 {
280         init();
281 }
282
283 void Texture::Loader::init()
284 {
285         levels = 0;
286         if(Resources *res = dynamic_cast<Resources *>(coll))
287                 srgb = res->get_srgb_conversion();
288         else
289                 srgb = false;
290
291         add("external_image", &Loader::external_image);
292         add("filter", &Loader::filter);
293         add("generate_mipmap", &Loader::generate_mipmap);
294         add("image_data", &Loader::image_data);
295         add("mag_filter", &Loader::mag_filter);
296         add("max_anisotropy", &Loader::max_anisotropy);
297         add("min_filter", &Loader::min_filter);
298         add("mipmap_levels", &Loader::mipmap_levels);
299         add("sampler",    &Loader::sampler);
300         add("wrap",       &Loader::wrap);
301         add("wrap_r",     &Loader::wrap_r);
302         add("wrap_s",     &Loader::wrap_s);
303         add("wrap_t",     &Loader::wrap_t);
304 }
305
306 unsigned Texture::Loader::get_levels() const
307 {
308         return (is_mipmapped(obj.default_sampler.get_min_filter()) ? levels : 1);
309 }
310
311 #pragma GCC diagnostic push
312 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
313 void Texture::Loader::external_image(const string &fn)
314 {
315         Graphics::Image img;
316         RefPtr<IO::Seekable> io = get_collection().open_raw(fn);
317         if(!io)
318                 throw IO::file_not_found(fn);
319         img.load_io(*io);
320
321         obj.image(img, get_levels(), srgb);
322 }
323
324 void Texture::Loader::filter(TextureFilter f)
325 {
326         obj.set_filter(f);
327 }
328
329 void Texture::Loader::generate_mipmap(bool gm)
330 {
331         obj.set_auto_generate_mipmap(gm);
332 }
333
334 void Texture::Loader::image_data(const string &data)
335 {
336         Graphics::Image img;
337         IO::Memory mem(data.data(), data.size());
338         img.load_io(mem);
339
340         obj.image(img, get_levels(), srgb);
341 }
342
343 void Texture::Loader::mag_filter(TextureFilter f)
344 {
345         obj.set_mag_filter(f);
346 }
347
348 void Texture::Loader::max_anisotropy(float a)
349 {
350         obj.set_max_anisotropy(a);
351 }
352
353 void Texture::Loader::min_filter(TextureFilter f)
354 {
355         obj.set_min_filter(f);
356 }
357
358 void Texture::Loader::mipmap_levels(unsigned l)
359 {
360         levels = l;
361 }
362
363 void Texture::Loader::sampler()
364 {
365         load_sub(obj.default_sampler);
366 }
367
368 void Texture::Loader::wrap(TextureWrap w)
369 {
370         obj.set_wrap(w);
371 }
372
373 void Texture::Loader::wrap_r(TextureWrap w)
374 {
375         obj.set_wrap_r(w);
376 }
377
378 void Texture::Loader::wrap_s(TextureWrap w)
379 {
380         obj.set_wrap_s(w);
381 }
382
383 void Texture::Loader::wrap_t(TextureWrap w)
384 {
385         obj.set_wrap_t(w);
386 }
387 #pragma GCC diagnostic pop
388
389 } // namespace GL
390 } // namespace Msp