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