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