]> git.tdb.fi Git - libs/gl.git/blob - source/texture.cpp
Support samplers as independent objects
[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)
197 {
198         load_image(fn, 0U);
199 }
200
201 void Texture::load_image(const string &fn, unsigned lv)
202 {
203         Graphics::Image img;
204         img.load_file(fn);
205
206         image(img, lv);
207 }
208
209 void Texture::image(const Graphics::Image &img, bool)
210 {
211         image(img, 0U);
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                 if(!unit.get_sampler())
242                         default_sampler.bind_to(i);
243         }
244 }
245
246 const Texture *Texture::current(unsigned i)
247 {
248         return TexUnit::get_unit(i).get_texture();
249 }
250
251 void Texture::unbind_from(unsigned i)
252 {
253         TexUnit &unit = TexUnit::get_unit(i);
254         const Texture *cur = unit.get_texture();
255         if(unit.set_texture(0))
256         {
257                 if(ARB_direct_state_access)
258                         glBindTextureUnit(i, 0);
259                 else
260                 {
261                         unit.bind();
262                         glBindTexture(cur->target, 0);
263                 }
264
265                 if(unit.get_sampler()==&cur->default_sampler)
266                         Sampler::unbind_from(i);
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
287         add("external_image", &Loader::external_image);
288         add("external_image_srgb", &Loader::external_image);
289         add("filter", &Loader::filter);
290         add("generate_mipmap", &Loader::generate_mipmap);
291         add("image_data", &Loader::image_data);
292         add("mag_filter", &Loader::mag_filter);
293         add("max_anisotropy", &Loader::max_anisotropy);
294         add("min_filter", &Loader::min_filter);
295         add("mipmap_levels", &Loader::mipmap_levels);
296         add("sampler",    &Loader::sampler);
297         add("wrap",       &Loader::wrap);
298         add("wrap_r",     &Loader::wrap_r);
299         add("wrap_s",     &Loader::wrap_s);
300         add("wrap_t",     &Loader::wrap_t);
301 }
302
303 unsigned Texture::Loader::get_levels() const
304 {
305         return (is_mipmapped(obj.default_sampler.get_min_filter()) ? levels : 1);
306 }
307
308 #pragma GCC diagnostic push
309 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
310 void Texture::Loader::load_external_image(Graphics::Image &img, const std::string &fn)
311 {
312         RefPtr<IO::Seekable> io = get_collection().open_raw(fn);
313         if(!io)
314                 throw IO::file_not_found(fn);
315         img.load_io(*io);
316 }
317
318 void Texture::Loader::external_image(const string &fn)
319 {
320         obj.use_srgb_format = false;
321         external_image_common(fn);
322 }
323
324 void Texture::Loader::external_image_srgb(const string &fn)
325 {
326         obj.use_srgb_format = true;
327         external_image_common(fn);
328 }
329
330 void Texture::Loader::external_image_common(const string &fn)
331 {
332         if(obj.manager)
333                 obj.manager->set_resource_location(obj, get_collection(), fn);
334         else
335         {
336                 Graphics::Image img;
337                 load_external_image(img, fn);
338                 obj.image(img, get_levels());
339         }
340 }
341
342 void Texture::Loader::filter(TextureFilter f)
343 {
344         obj.set_filter(f);
345 }
346
347 void Texture::Loader::generate_mipmap(bool gm)
348 {
349         obj.set_auto_generate_mipmap(gm);
350 }
351
352 void Texture::Loader::image_data(const string &data)
353 {
354         Graphics::Image img;
355         IO::Memory mem(data.data(), data.size());
356         img.load_io(mem);
357
358         obj.image(img, get_levels());
359 }
360
361 void Texture::Loader::mag_filter(TextureFilter f)
362 {
363         obj.set_mag_filter(f);
364 }
365
366 void Texture::Loader::max_anisotropy(float a)
367 {
368         obj.set_max_anisotropy(a);
369 }
370
371 void Texture::Loader::min_filter(TextureFilter f)
372 {
373         obj.set_min_filter(f);
374 }
375
376 void Texture::Loader::mipmap_levels(unsigned l)
377 {
378         levels = l;
379 }
380
381 void Texture::Loader::sampler()
382 {
383         load_sub(obj.default_sampler);
384 }
385
386 void Texture::Loader::wrap(TextureWrap w)
387 {
388         obj.set_wrap(w);
389 }
390
391 void Texture::Loader::wrap_r(TextureWrap w)
392 {
393         obj.set_wrap_r(w);
394 }
395
396 void Texture::Loader::wrap_s(TextureWrap w)
397 {
398         obj.set_wrap_s(w);
399 }
400
401 void Texture::Loader::wrap_t(TextureWrap w)
402 {
403         obj.set_wrap_t(w);
404 }
405 #pragma GCC diagnostic pop
406
407 } // namespace GL
408 } // namespace Msp