]> git.tdb.fi Git - libs/gl.git/blob - source/texture.cpp
Refactor texture external image loading into a helper function
[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         format(RGB8),
29         storage_fmt(RGB8),
30         swizzle(NO_SWIZZLE),
31         auto_gen_mipmap(false),
32         default_sampler(*this)
33 {
34         if(m)
35                 set_manager(m);
36         else if(ARB_direct_state_access)
37                 glCreateTextures(target, 1, &id);
38         else
39                 glGenTextures(1, &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::set_format(PixelFormat fmt)
52 {
53         PixelComponents comp = get_components(fmt);
54         PixelComponents st_comp = comp;
55         FormatSwizzle swiz = NO_SWIZZLE;
56         switch(comp)
57         {
58         case LUMINANCE:
59                 st_comp = RED;
60                 swiz = R_TO_LUMINANCE;
61                 break;
62         case LUMINANCE_ALPHA:
63                 st_comp = RG;
64                 swiz = RG_TO_LUMINANCE_ALPHA;
65                 break;
66         case BGR:
67                 st_comp = RGB;
68                 swiz = RGB_TO_BGR;
69                 break;
70         case BGRA:
71                 st_comp = RGBA;
72                 swiz = RGB_TO_BGR;
73                 break;
74         default:;
75         }
76
77         PixelFormat st_fmt = make_pixelformat(st_comp, get_component_type(fmt));
78         require_pixelformat(st_fmt);
79         if(swiz!=NO_SWIZZLE)
80                 static Require _req(ARB_texture_swizzle);
81
82         format = fmt;
83         storage_fmt = st_fmt;
84         swizzle = swiz;
85 }
86
87 void Texture::apply_swizzle()
88 {
89         if(swizzle==NO_SWIZZLE)
90                 return;
91
92         if(get_gl_api()==OPENGL_ES2)
93         {
94                 set_parameter_i(GL_TEXTURE_SWIZZLE_R, swizzle_orders[swizzle*4]);
95                 set_parameter_i(GL_TEXTURE_SWIZZLE_G, swizzle_orders[swizzle*4+1]);
96                 set_parameter_i(GL_TEXTURE_SWIZZLE_B, swizzle_orders[swizzle*4+2]);
97                 set_parameter_i(GL_TEXTURE_SWIZZLE_A, swizzle_orders[swizzle*4+3]);
98         }
99         else
100         {
101                 if(ARB_direct_state_access)
102                         glTextureParameteriv(id, GL_TEXTURE_SWIZZLE_RGBA, swizzle_orders+swizzle*4);
103                 else
104                         glTexParameteriv(target, GL_TEXTURE_SWIZZLE_RGBA, swizzle_orders+swizzle*4);
105         }
106 }
107
108 void Texture::set_parameter_i(GLenum param, int value) const
109 {
110         if(ARB_direct_state_access)
111                 glTextureParameteri(id, param, value);
112         else
113                 glTexParameteri(target, param, value);
114 }
115
116 void Texture::set_min_filter(TextureFilter f)
117 {
118         default_sampler.set_min_filter(f);
119 }
120
121 void Texture::set_mag_filter(TextureFilter f)
122 {
123         default_sampler.set_mag_filter(f);
124 }
125
126 void Texture::set_filter(TextureFilter f)
127 {
128         default_sampler.set_filter(f);
129 }
130
131 void Texture::set_max_anisotropy(float a)
132 {
133         default_sampler.set_max_anisotropy(a);
134 }
135
136 void Texture::set_wrap(TextureWrap w)
137 {
138         default_sampler.set_wrap(w);
139 }
140
141 void Texture::set_wrap_s(TextureWrap w)
142 {
143         default_sampler.set_wrap_s(w);
144 }
145
146 void Texture::set_wrap_t(TextureWrap w)
147 {
148         default_sampler.set_wrap_t(w);
149 }
150
151 void Texture::set_wrap_r(TextureWrap w)
152 {
153         default_sampler.set_wrap_r(w);
154 }
155
156 bool Texture::can_generate_mipmap()
157 {
158         return EXT_framebuffer_object;
159 }
160
161 void Texture::generate_mipmap()
162 {
163         // glGenerateMipmap is defined here
164         static Require _req(EXT_framebuffer_object);
165
166         if(ARB_direct_state_access)
167                 glGenerateTextureMipmap(id);
168         else
169         {
170                 BindRestore _bind(this);
171                 glGenerateMipmap(target);
172         }
173 }
174
175 void Texture::set_auto_generate_mipmap(bool gm)
176 {
177         if(gm)
178                 static Require _req(EXT_framebuffer_object);
179
180         auto_gen_mipmap = gm;
181 }
182
183 void Texture::set_compare_enabled(bool c)
184 {
185         if(c)
186                 default_sampler.set_compare(default_sampler.get_compare_function());
187         else
188                 default_sampler.disable_compare();
189 }
190
191 void Texture::set_compare_func(Predicate f)
192 {
193         default_sampler.set_compare(f);
194 }
195
196 void Texture::load_image(const string &fn, bool srgb)
197 {
198         load_image(fn, 0, srgb);
199 }
200
201 void Texture::load_image(const string &fn, unsigned lv, bool srgb)
202 {
203         Graphics::Image img;
204         img.load_file(fn);
205
206         image(img, lv, srgb);
207 }
208
209 void Texture::image(const Graphics::Image &img, bool srgb)
210 {
211         image(img, 0, srgb);
212 }
213
214 void Texture::bind_to(unsigned i) const
215 {
216         if(!id)
217         {
218                 if(manager)
219                         manager->resource_used(*this);
220                 if(!id)
221                 {
222                         unbind_from(i);
223                         return;
224                 }
225         }
226
227         TexUnit &unit = TexUnit::get_unit(i);
228         if(unit.set_texture(this))
229         {
230                 if(manager)
231                         manager->resource_used(*this);
232
233                 if(ARB_direct_state_access)
234                         glBindTextureUnit(i, id);
235                 else
236                 {
237                         unit.bind();
238                         glBindTexture(target, id);
239                 }
240
241                 default_sampler.bind_to(i);
242         }
243 }
244
245 const Texture *Texture::current(unsigned i)
246 {
247         return TexUnit::get_unit(i).get_texture();
248 }
249
250 void Texture::unbind_from(unsigned i)
251 {
252         TexUnit &unit = TexUnit::get_unit(i);
253         const Texture *cur = unit.get_texture();
254         if(unit.set_texture(0))
255         {
256                 if(ARB_direct_state_access)
257                         glBindTextureUnit(i, 0);
258                 else
259                 {
260                         unit.bind();
261                         glBindTexture(cur->target, 0);
262                 }
263         }
264 }
265
266
267 Texture::Loader::Loader(Texture &t):
268         DataFile::CollectionObjectLoader<Texture>(t, 0)
269 {
270         init();
271 }
272
273 Texture::Loader::Loader(Texture &t, Collection &c):
274         DataFile::CollectionObjectLoader<Texture>(t, &c)
275 {
276         init();
277 }
278
279 void Texture::Loader::init()
280 {
281         levels = 0;
282         if(Resources *res = dynamic_cast<Resources *>(coll))
283                 srgb = res->get_srgb_conversion();
284         else
285                 srgb = false;
286
287         add("external_image", &Loader::external_image);
288         add("filter", &Loader::filter);
289         add("generate_mipmap", &Loader::generate_mipmap);
290         add("image_data", &Loader::image_data);
291         add("mag_filter", &Loader::mag_filter);
292         add("max_anisotropy", &Loader::max_anisotropy);
293         add("min_filter", &Loader::min_filter);
294         add("mipmap_levels", &Loader::mipmap_levels);
295         add("sampler",    &Loader::sampler);
296         add("wrap",       &Loader::wrap);
297         add("wrap_r",     &Loader::wrap_r);
298         add("wrap_s",     &Loader::wrap_s);
299         add("wrap_t",     &Loader::wrap_t);
300 }
301
302 unsigned Texture::Loader::get_levels() const
303 {
304         return (is_mipmapped(obj.default_sampler.get_min_filter()) ? levels : 1);
305 }
306
307 #pragma GCC diagnostic push
308 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
309 void Texture::Loader::load_external_image(Graphics::Image &img, const std::string &fn)
310 {
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
317 void Texture::Loader::external_image(const string &fn)
318 {
319         Graphics::Image img;
320         load_external_image(img, fn);
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