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