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