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