]> git.tdb.fi Git - libs/gl.git/blob - source/core/pixelformat.cpp
Fix loading sRGB external images for textures
[libs/gl.git] / source / core / pixelformat.cpp
1 #include <msp/gl/extensions/arb_texture_float.h>
2 #include <msp/io/print.h>
3 #include <msp/strings/format.h>
4 #include "pixelformat.h"
5
6 using namespace std;
7
8 namespace Msp {
9 namespace GL {
10
11 void operator>>(const LexicalConverter &conv, PixelComponents &comp)
12 {
13         if(conv.get()=="STENCIL_INDEX")
14                 comp = STENCIL_INDEX;
15         else if(conv.get()=="DEPTH_COMPONENT")
16                 comp = DEPTH_COMPONENT;
17         else if(conv.get()=="RED")
18                 comp = RED;
19         else if(conv.get()=="RG")
20                 comp = RG;
21         else if(conv.get()=="RGB")
22                 comp = RGB;
23         else if(conv.get()=="RGBA")
24                 comp = RGBA;
25         else if(conv.get()=="BGR")
26                 comp = BGR;
27         else if(conv.get()=="BGRA")
28                 comp = BGRA;
29         else if(conv.get()=="LUMINANCE")
30                 comp = LUMINANCE;
31         else if(conv.get()=="LUMINANCE_ALPHA")
32                 comp = LUMINANCE_ALPHA;
33         else
34                 throw lexical_error(format("conversion of '%s' to PixelComponents", conv.get()));
35 }
36
37 void operator>>(const LexicalConverter &conv, PixelFormat &fmt)
38 {
39         if(conv.get()=="R8")
40                 fmt = R8;
41         else if(conv.get()=="R16F")
42                 fmt = R16F;
43         else if(conv.get()=="R32F")
44                 fmt = R32F;
45         else if(conv.get()=="RG8")
46                 fmt = RG8;
47         else if(conv.get()=="RG16F")
48                 fmt = RG16F;
49         else if(conv.get()=="RG32F")
50                 fmt = RG32F;
51         else if(conv.get()=="RGB8")
52                 fmt = RGB8;
53         else if(conv.get()=="RGB16F")
54                 fmt = RGB16F;
55         else if(conv.get()=="RGB32F")
56                 fmt = RGB32F;
57         else if(conv.get()=="RGBA8")
58                 fmt = RGBA8;
59         else if(conv.get()=="RGBA16F")
60                 fmt = RGBA16F;
61         else if(conv.get()=="RGBA32F")
62                 fmt = RGBA32F;
63         else if(conv.get()=="SRGB8")
64                 fmt = SRGB8;
65         else if(conv.get()=="SRGB8_ALPHA8")
66                 fmt = SRGB8_ALPHA8;
67         else if(conv.get()=="BGR8")
68                 fmt = BGR8;
69         else if(conv.get()=="BGRA8")
70                 fmt = BGRA8;
71         else if(conv.get()=="LUMINANCE8")
72                 fmt = LUMINANCE8;
73         else if(conv.get()=="LUMINANCE8_ALPHA8")
74                 fmt = LUMINANCE8_ALPHA8;
75         else if(conv.get()=="DEPTH_COMPONENT16")
76                 fmt = DEPTH_COMPONENT16;
77         else if(conv.get()=="DEPTH_COMPONENT24")
78                 fmt = DEPTH_COMPONENT24;
79         else if(conv.get()=="DEPTH_COMPONENT32")
80                 fmt = DEPTH_COMPONENT32;
81         else if(conv.get()=="DEPTH_COMPONENT32F")
82                 fmt = DEPTH_COMPONENT32F;
83         else
84         {
85                 if(conv.get()=="SRGB")
86                         fmt = SRGB8;
87                 else if(conv.get()=="SRGB_ALPHA")
88                         fmt = SRGB8_ALPHA8;
89                 else
90                 {
91                         PixelComponents comp;
92                         conv >> comp;
93                         fmt = make_pixelformat(comp, (comp==DEPTH_COMPONENT ? FLOAT : UNSIGNED_BYTE));
94                 }
95                 IO::print(IO::cerr, "Warning: deprecated conversion of '%s' to PixelFormat\n", conv.get());
96         }
97 }
98
99 PixelComponents pixelformat_from_graphics(Graphics::PixelFormat pf)
100 {
101         switch(pf)
102         {
103         case Graphics::LUMINANCE: return LUMINANCE;
104         case Graphics::LUMINANCE_ALPHA: return LUMINANCE_ALPHA;
105         case Graphics::RGB: return RGB;
106         case Graphics::RGBX:
107         case Graphics::RGBA: return RGBA;
108         case Graphics::BGR: return BGR;
109         case Graphics::BGRX:
110         case Graphics::BGRA: return BGRA;
111         default: throw invalid_argument("pixelformat_from_graphics");
112         }
113 }
114
115 PixelComponents storage_pixelformat_from_graphics(Graphics::PixelFormat pf)
116 {
117 #pragma GCC diagnostic push
118 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
119         switch(pf)
120         {
121         case Graphics::RGBX:
122         case Graphics::BGR:
123         case Graphics::BGRX: return RGB;
124         case Graphics::BGRA: return RGBA;
125         default: return pixelformat_from_graphics(pf);
126         }
127 #pragma GCC diagnostic pop
128 }
129
130 PixelFormat pixelformat_from_image(const Graphics::Image &image)
131 {
132 #pragma GCC diagnostic push
133 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
134         PixelComponents comp = pixelformat_from_graphics(image.get_format());
135 #pragma GCC diagnostic pop
136         return make_pixelformat(comp, UNSIGNED_BYTE);
137 }
138
139 PixelFormat make_pixelformat(PixelComponents comp, DataType type, bool srgb)
140 {
141         if(srgb && type!=UNSIGNED_BYTE && comp!=RGB && comp!=RGBA && comp!=BGR && comp!=BGRA)
142                 throw invalid_argument("make_pixelformat");
143
144         switch(comp)
145         {
146         case RED:
147                 switch(type)
148                 {
149                 case UNSIGNED_BYTE: return R8;
150                 case HALF_FLOAT: return R16F;
151                 case FLOAT: return R32F;
152                 default: throw invalid_argument("make_pixelformat");
153                 }
154         case RG:
155                 switch(type)
156                 {
157                 case UNSIGNED_BYTE: return RG8;
158                 case HALF_FLOAT: return RG16F;
159                 case FLOAT: return RG32F;
160                 default: throw invalid_argument("make_pixelformat");
161                 }
162         case RGB:
163                 switch(type)
164                 {
165                 case UNSIGNED_BYTE: return (srgb ? SRGB8 : RGB8);
166                 case HALF_FLOAT: return RGB16F;
167                 case FLOAT: return RGB32F;
168                 default: throw invalid_argument("make_pixelformat");
169                 }
170         case RGBA:
171                 switch(type)
172                 {
173                 case UNSIGNED_BYTE: return (srgb ? SRGB8_ALPHA8 : RGBA8);
174                 case HALF_FLOAT: return RGBA16F;
175                 case FLOAT: return RGBA32F;
176                 default: throw invalid_argument("make_pixelformat");
177                 }
178         case BGR:
179                 if(type!=UNSIGNED_BYTE)
180                         throw invalid_argument("make_pixelformat");
181                 return (srgb ? BGR8 : SBGR8);
182         case BGRA:
183                 if(type!=UNSIGNED_BYTE)
184                         throw invalid_argument("make_pixelformat");
185                 return (srgb ? BGRA8 : SBGR8_ALPHA8);
186         case LUMINANCE:
187                 if(type!=UNSIGNED_BYTE)
188                         throw invalid_argument("make_pixelformat");
189                 return LUMINANCE8;
190         case LUMINANCE_ALPHA:
191                 if(type!=UNSIGNED_BYTE)
192                         throw invalid_argument("make_pixelformat");
193                 return LUMINANCE8;
194         case STENCIL_INDEX:
195                 if(type!=UNSIGNED_BYTE)
196                         throw invalid_argument("make_pixelformat");
197                 return STENCIL_INDEX8;
198         case DEPTH_COMPONENT:
199                 switch(type)
200                 {
201                 case UNSIGNED_SHORT: return DEPTH_COMPONENT16;
202                 case UNSIGNED_INT: return DEPTH_COMPONENT32;
203                 case FLOAT: return DEPTH_COMPONENT32F;
204                 default: throw invalid_argument("make_pixelformat");
205                 }
206         default:
207                 throw invalid_argument("make_pixelformat");
208         }
209 }
210
211 PixelFormat get_base_pixelformat(PixelFormat pf)
212 {
213         switch(pf)
214         {
215         case SRGB8: return RGB8;
216         case SRGB8_ALPHA8: return RGBA8;
217         default: return pf;
218         }
219 }
220
221 PixelComponents get_components(PixelFormat pf)
222 {
223         switch(pf)
224         {
225         case R8:
226         case R16F:
227         case R32F: return RED;
228         case RG8:
229         case RG16F:
230         case RG32F: return RG;
231         case RGB8:
232         case RGB16F:
233         case RGB32F:
234         case SRGB8: return RGB;
235         case RGBA8:
236         case RGBA16F:
237         case RGBA32F:
238         case SRGB8_ALPHA8: return RGBA;
239         case BGR8:
240         case SBGR8: return BGR;
241         case BGRA8:
242         case SBGR8_ALPHA8: return BGRA;
243         case LUMINANCE8: return LUMINANCE;
244         case LUMINANCE8_ALPHA8: return LUMINANCE_ALPHA;
245         case STENCIL_INDEX8: return STENCIL_INDEX;
246         case DEPTH_COMPONENT16:
247         case DEPTH_COMPONENT24:
248         case DEPTH_COMPONENT32:
249         case DEPTH_COMPONENT32F: return DEPTH_COMPONENT;
250         default: throw invalid_argument("get_components");
251         }
252 }
253
254 PixelFormat get_default_sized_pixelformat(PixelComponents comp)
255 {
256         DataType type = UNSIGNED_BYTE;
257         if(comp==DEPTH_COMPONENT)
258         {
259                 if(get_gl_api()==OPENGL_ES2 && !ARB_depth_buffer_float)
260                         type = UNSIGNED_SHORT;
261                 else
262                         type = FLOAT;
263         }
264         return make_pixelformat(comp, type);
265 }
266
267 PixelFormat get_srgb_pixelformat(PixelFormat pf)
268 {
269         switch(pf)
270         {
271         case RGB8: return SRGB8;
272         case RGBA8: return SRGB8_ALPHA8;
273         default: return pf;
274         }
275 }
276
277 unsigned get_component_count(PixelComponents comp)
278 {
279         switch(comp)
280         {
281         case RED:
282         case LUMINANCE:
283         case DEPTH_COMPONENT:
284         case STENCIL_INDEX:
285                 return 1;
286         case RG:
287         case LUMINANCE_ALPHA:
288                 return 2;
289         case RGB:
290         case BGR:
291                 return 3;
292         case RGBA:
293         case BGRA:
294                 return 4;
295         default:
296                 throw invalid_argument("get_component_count");
297         }
298 }
299
300 DataType get_component_type(PixelFormat pf)
301 {
302         switch(pf)
303         {
304         case R8:
305         case RG8:
306         case RGB8:
307         case RGBA8:
308         case SRGB8:
309         case SRGB8_ALPHA8:
310         case BGR8:
311         case BGRA8:
312         case SBGR8:
313         case SBGR8_ALPHA8:
314         case LUMINANCE8:
315         case LUMINANCE8_ALPHA8:
316                 return UNSIGNED_BYTE;
317         case R16F:
318         case RG16F:
319         case RGB16F:
320         case RGBA16F:
321                 return HALF_FLOAT;
322         case DEPTH_COMPONENT16:
323                 return UNSIGNED_SHORT;
324         case R32F:
325         case RG32F:
326         case RGB32F:
327         case RGBA32F:
328         case DEPTH_COMPONENT32:
329                 return UNSIGNED_INT;
330         case DEPTH_COMPONENT32F:
331                 return FLOAT;
332         case DEPTH_COMPONENT24:
333                 // There's no DataType value with 24-bit size
334         default:
335                 throw invalid_argument("get_component_type");
336         }
337 }
338
339 bool is_srgb(PixelFormat pf)
340 {
341         return (pf==SRGB8 || pf==SRGB8_ALPHA8 || pf==SBGR8 || pf==SBGR8_ALPHA8);
342 }
343
344 unsigned get_pixel_size(PixelFormat pf)
345 {
346         return get_component_count(pf)*get_type_size(get_component_type(pf));
347 }
348
349 void require_pixelformat(PixelFormat pf)
350 {
351         /* TODO These checks are only accurate for textures.  On OpenGL ES some
352         formats are allowed for render buffers earlier than textures.  In particular
353         it's possible to create a 16-bit depth renderbuffer on OpenGL ES 2.0 but
354         depth textures are only available with 3.0 or the OES_depth_texture
355         extension.*/
356         switch(pf)
357         {
358         case RGB8:
359         case RGBA8:
360                 { static Require _req(OES_required_internalformat); }
361                 break;
362         case R8:
363         case RG8:
364                 { static Require _req(ARB_texture_rg); }
365                 break;
366         case R16F:
367         case R32F:
368         case RG16F:
369         case RG32F:
370                 { static Require _req(ARB_texture_rg); }
371                 { static Require _req(ARB_texture_float); }
372                 break;
373         case RGB16F:
374         case RGB32F:
375         case RGBA16F:
376         case RGBA32F:
377                 { static Require _req(ARB_texture_float); }
378                 break;
379         case SRGB8:
380         case SRGB8_ALPHA8:
381                 { static Require _req(EXT_texture_sRGB); }
382                 break;
383         case DEPTH_COMPONENT16:
384         case DEPTH_COMPONENT24:
385         case DEPTH_COMPONENT32:
386                 { static Require _req(ARB_depth_texture); }
387                 { static Require _req(OES_required_internalformat); }
388                 break;
389         case DEPTH_COMPONENT32F:
390                 { static Require _req(ARB_depth_buffer_float); }
391                 break;
392         case STENCIL_INDEX8:
393                 { static Require _req(OES_texture_stencil8); }
394                 break;
395         default:
396                 throw invalid_argument("require_pixelformat");
397         }
398 }
399
400 } // namespace GL
401 } // namespace Msp