]> git.tdb.fi Git - libs/gl.git/blob - source/core/texture.cpp
b40046705b32bdfbecd459b56ce5e9b7c81ae4d9
[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/gl/extensions/khr_debug.h>
5 #include <msp/io/memory.h>
6 #include "error.h"
7 #include "resourcemanager.h"
8 #include "resources.h"
9 #include "texture.h"
10
11 using namespace std;
12
13 namespace Msp {
14 namespace GL {
15
16 int Texture::swizzle_orders[] =
17 {
18         GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA,
19         GL_RED, GL_RED, GL_RED, GL_ONE,
20         GL_RED, GL_RED, GL_RED, GL_GREEN,
21         GL_BLUE, GL_GREEN, GL_RED, GL_ALPHA
22 };
23
24 Texture *Texture::scratch_binding = 0;
25
26 Texture::Texture(GLenum t, ResourceManager *m):
27         id(0),
28         target(t),
29         format(RGB8),
30         storage_fmt(RGB8),
31         swizzle(NO_SWIZZLE),
32         use_srgb_format(false),
33         auto_gen_mipmap(false)
34 {
35         if(m)
36                 set_manager(m);
37         else
38                 generate_id();
39
40         static bool alignment_init = false;
41         if(!alignment_init)
42         {
43                 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
44                 alignment_init = true;
45         }
46 }
47
48 Texture::~Texture()
49 {
50         if(this==scratch_binding)
51                 unbind_scratch();
52         if(id)
53                 glDeleteTextures(1, &id);
54 }
55
56 void Texture::generate_id()
57 {
58         if(id)
59                 throw invalid_operation("Texture::generate_id");
60         if(ARB_direct_state_access)
61                 glCreateTextures(target, 1, &id);
62         else
63                 glGenTextures(1, &id);
64
65 #ifdef DEBUG
66         if(!debug_name.empty() && KHR_debug)
67                 glObjectLabel(GL_TEXTURE, id, debug_name.size(), debug_name.c_str());
68 #endif
69 }
70
71 void Texture::set_format(PixelFormat fmt)
72 {
73         PixelComponents comp = get_components(fmt);
74         PixelComponents st_comp = comp;
75         FormatSwizzle swiz = NO_SWIZZLE;
76         switch(comp)
77         {
78         case LUMINANCE:
79                 st_comp = RED;
80                 swiz = R_TO_LUMINANCE;
81                 break;
82         case LUMINANCE_ALPHA:
83                 st_comp = RG;
84                 swiz = RG_TO_LUMINANCE_ALPHA;
85                 break;
86         case BGR:
87                 st_comp = RGB;
88                 swiz = RGB_TO_BGR;
89                 break;
90         case BGRA:
91                 st_comp = RGBA;
92                 swiz = RGB_TO_BGR;
93                 break;
94         default:;
95         }
96
97         PixelFormat st_fmt = make_pixelformat(st_comp, get_component_type(fmt), is_srgb(fmt));
98         require_pixelformat(st_fmt);
99         if(swiz!=NO_SWIZZLE)
100                 static Require _req(ARB_texture_swizzle);
101
102         format = fmt;
103         storage_fmt = st_fmt;
104         swizzle = swiz;
105 }
106
107 void Texture::apply_swizzle()
108 {
109         if(swizzle==NO_SWIZZLE)
110                 return;
111
112         if(get_gl_api()==OPENGL_ES2)
113         {
114                 set_parameter_i(GL_TEXTURE_SWIZZLE_R, swizzle_orders[swizzle*4]);
115                 set_parameter_i(GL_TEXTURE_SWIZZLE_G, swizzle_orders[swizzle*4+1]);
116                 set_parameter_i(GL_TEXTURE_SWIZZLE_B, swizzle_orders[swizzle*4+2]);
117                 set_parameter_i(GL_TEXTURE_SWIZZLE_A, swizzle_orders[swizzle*4+3]);
118         }
119         else
120         {
121                 if(ARB_direct_state_access)
122                         glTextureParameteriv(id, GL_TEXTURE_SWIZZLE_RGBA, swizzle_orders+swizzle*4);
123                 else
124                         glTexParameteriv(target, GL_TEXTURE_SWIZZLE_RGBA, swizzle_orders+swizzle*4);
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 bool Texture::can_generate_mipmap()
137 {
138         return EXT_framebuffer_object;
139 }
140
141 void Texture::generate_mipmap()
142 {
143         // glGenerateMipmap is defined here
144         static Require _req(EXT_framebuffer_object);
145
146         if(ARB_direct_state_access)
147                 glGenerateTextureMipmap(id);
148         else
149         {
150                 bind_scratch();
151                 glGenerateMipmap(target);
152         }
153 }
154
155 void Texture::set_auto_generate_mipmap(bool gm)
156 {
157         if(gm)
158                 static Require _req(EXT_framebuffer_object);
159
160         auto_gen_mipmap = gm;
161 }
162
163 void Texture::load_image(const string &fn, bool)
164 {
165         load_image(fn, 0U);
166 }
167
168 void Texture::load_image(const string &fn, unsigned lv)
169 {
170         Graphics::Image img;
171         img.load_file(fn);
172
173         image(img, lv);
174 }
175
176 void Texture::image(const Graphics::Image &img, bool)
177 {
178         image(img, 0U);
179 }
180
181 void Texture::set_debug_name(const string &name)
182 {
183 #ifdef DEBUG
184         debug_name = name;
185         if(id && KHR_debug)
186                 glObjectLabel(GL_TEXTURE, id, name.size(), name.c_str());
187 #else
188         (void)name;
189 #endif
190 }
191
192 void Texture::bind_scratch()
193 {
194         if(!scratch_binding)
195                 glActiveTexture(GL_TEXTURE0);
196         if(scratch_binding!=this)
197         {
198                 if(scratch_binding && scratch_binding->target!=target)
199                         glBindTexture(scratch_binding->target, 0);
200                 glBindTexture(target, id);
201                 scratch_binding = this;
202         }
203 }
204
205 void Texture::unbind_scratch()
206 {
207         if(scratch_binding)
208         {
209                 glBindTexture(scratch_binding->target, 0);
210                 scratch_binding = 0;
211         }
212 }
213
214
215 Texture::Loader::Loader(Texture &t):
216         DataFile::CollectionObjectLoader<Texture>(t, 0)
217 {
218         init();
219 }
220
221 Texture::Loader::Loader(Texture &t, Collection &c):
222         DataFile::CollectionObjectLoader<Texture>(t, &c)
223 {
224         init();
225 }
226
227 void Texture::Loader::init()
228 {
229         levels = 0;
230
231         add("external_image", &Loader::external_image);
232         add("external_image_srgb", &Loader::external_image_srgb);
233         add("generate_mipmap", &Loader::generate_mipmap);
234         add("image_data", &Loader::image_data);
235         add("mipmap_levels", &Loader::mipmap_levels);
236 }
237
238 void Texture::Loader::load_external_image(Graphics::Image &img, const string &fn)
239 {
240         RefPtr<IO::Seekable> io = get_collection().open_raw(fn);
241         if(!io)
242                 throw IO::file_not_found(fn);
243         img.load_io(*io);
244 }
245
246 void Texture::Loader::external_image(const string &fn)
247 {
248         obj.use_srgb_format = false;
249         external_image_common(fn);
250 }
251
252 void Texture::Loader::external_image_srgb(const string &fn)
253 {
254         obj.use_srgb_format = true;
255         external_image_common(fn);
256 }
257
258 void Texture::Loader::external_image_common(const string &fn)
259 {
260         if(obj.manager)
261                 obj.manager->set_resource_location(obj, get_collection(), fn);
262         else
263         {
264                 Graphics::Image img;
265                 load_external_image(img, fn);
266                 obj.image(img, levels);
267         }
268 }
269
270 void Texture::Loader::generate_mipmap(bool gm)
271 {
272         obj.set_auto_generate_mipmap(gm);
273 }
274
275 void Texture::Loader::image_data(const string &data)
276 {
277         if(obj.manager)
278         {
279                 obj.set_manager(0);
280                 if(!obj.id)
281                         obj.generate_id();
282         }
283
284         Graphics::Image img;
285         IO::Memory mem(data.data(), data.size());
286         img.load_io(mem);
287
288         obj.image(img, levels);
289 }
290
291 void Texture::Loader::mipmap_levels(unsigned l)
292 {
293         levels = l;
294 }
295
296 } // namespace GL
297 } // namespace Msp