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