]> git.tdb.fi Git - libs/gl.git/blob - source/pixelformat.cpp
Separate abstract pixel compositions from concrete pixel formats
[libs/gl.git] / source / 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 PixelFormat", 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()=="LUMINANCE8")
68                 fmt = LUMINANCE8;
69         else if(conv.get()=="LUMINANCE8_ALPHA8")
70                 fmt = LUMINANCE8_ALPHA8;
71         else if(conv.get()=="DEPTH_COMPONENT16")
72                 fmt = DEPTH_COMPONENT16;
73         else if(conv.get()=="DEPTH_COMPONENT24")
74                 fmt = DEPTH_COMPONENT24;
75         else if(conv.get()=="DEPTH_COMPONENT32")
76                 fmt = DEPTH_COMPONENT32;
77         else if(conv.get()=="DEPTH_COMPONENT32F")
78                 fmt = DEPTH_COMPONENT32F;
79         else
80         {
81                 PixelComponents comp;
82                 conv >> comp;
83                 fmt = make_pixelformat(comp, (comp==DEPTH_COMPONENT ? FLOAT : UNSIGNED_BYTE));
84                 IO::print(IO::cerr, "Warning: deprecated conversion of '%s' to PixelFormat\n", conv.get());
85         }
86 }
87
88 PixelComponents pixelformat_from_graphics(Graphics::PixelFormat pf)
89 {
90         switch(pf)
91         {
92         case Graphics::LUMINANCE: return LUMINANCE;
93         case Graphics::LUMINANCE_ALPHA: return LUMINANCE_ALPHA;
94         case Graphics::RGB: return RGB;
95         case Graphics::RGBX:
96         case Graphics::RGBA: return RGBA;
97         case Graphics::BGR: return BGR;
98         case Graphics::BGRX:
99         case Graphics::BGRA: return BGRA;
100         default: throw invalid_argument("pixelformat_from_graphics");
101         }
102 }
103
104 PixelComponents storage_pixelformat_from_graphics(Graphics::PixelFormat pf)
105 {
106 #pragma GCC diagnostic push
107 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
108         switch(pf)
109         {
110         case Graphics::RGBX:
111         case Graphics::BGR:
112         case Graphics::BGRX: return RGB;
113         case Graphics::BGRA: return RGBA;
114         default: return pixelformat_from_graphics(pf);
115         }
116 #pragma GCC diagnostic pop
117 }
118
119 PixelFormat pixelformat_from_image(const Graphics::Image &image)
120 {
121 #pragma GCC diagnostic push
122 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
123         PixelComponents comp = pixelformat_from_graphics(image.get_format());
124 #pragma GCC diagnostic pop
125         return make_pixelformat(comp, UNSIGNED_BYTE);
126 }
127
128 PixelFormat make_pixelformat(PixelComponents comp, DataType type, bool srgb)
129 {
130         if(srgb && type!=UNSIGNED_BYTE && comp!=RGB && comp!=RGBA)
131                 throw invalid_argument("make_pixelformat");
132
133         switch(comp)
134         {
135         case RED:
136                 switch(type)
137                 {
138                 case UNSIGNED_BYTE: return R8;
139                 case HALF_FLOAT: return R16F;
140                 case FLOAT: return R32F;
141                 default: throw invalid_argument("make_pixelformat");
142                 }
143         case RG:
144                 switch(type)
145                 {
146                 case UNSIGNED_BYTE: return RG8;
147                 case HALF_FLOAT: return RG16F;
148                 case FLOAT: return RG32F;
149                 default: throw invalid_argument("make_pixelformat");
150                 }
151         case RGB:
152                 switch(type)
153                 {
154                 case UNSIGNED_BYTE: return (srgb ? SRGB8 : RGB8);
155                 case HALF_FLOAT: return RGB16F;
156                 case FLOAT: return RGB32F;
157                 default: throw invalid_argument("make_pixelformat");
158                 }
159         case RGBA:
160                 switch(type)
161                 {
162                 case UNSIGNED_BYTE: return (srgb ? SRGB8_ALPHA8 : RGBA8);
163                 case HALF_FLOAT: return RGBA16F;
164                 case FLOAT: return RGBA32F;
165                 default: throw invalid_argument("make_pixelformat");
166                 }
167         case LUMINANCE:
168                 if(type!=UNSIGNED_BYTE)
169                         throw invalid_argument("make_pixelformat");
170                 return LUMINANCE8;
171         case LUMINANCE_ALPHA:
172                 if(type!=UNSIGNED_BYTE)
173                         throw invalid_argument("make_pixelformat");
174                 return LUMINANCE8;
175         case STENCIL_INDEX:
176                 if(type!=UNSIGNED_BYTE)
177                         throw invalid_argument("make_pixelformat");
178                 return STENCIL_INDEX8;
179         case DEPTH_COMPONENT:
180                 switch(type)
181                 {
182                 case UNSIGNED_SHORT: return DEPTH_COMPONENT16;
183                 case UNSIGNED_INT: return DEPTH_COMPONENT32;
184                 case FLOAT: return DEPTH_COMPONENT32F;
185                 default: throw invalid_argument("make_pixelformat");
186                 }
187         default:
188                 throw invalid_argument("make_pixelformat");
189         }
190 }
191
192 PixelFormat get_base_pixelformat(PixelFormat pf)
193 {
194         switch(pf)
195         {
196         case SRGB8: return RGB8;
197         case SRGB8_ALPHA8: return RGBA8;
198         default: return pf;
199         }
200 }
201
202 PixelComponents get_components(PixelFormat pf)
203 {
204         switch(pf)
205         {
206         case R8:
207         case R16F:
208         case R32F: return RED;
209         case RG8:
210         case RG16F:
211         case RG32F: return RG;
212         case RGB8:
213         case RGB16F:
214         case RGB32F:
215         case SRGB8: return RGB;
216         case RGBA8:
217         case RGBA16F:
218         case RGBA32F:
219         case SRGB8_ALPHA8: return RGBA;
220         case LUMINANCE8: return LUMINANCE;
221         case LUMINANCE8_ALPHA8: return LUMINANCE_ALPHA;
222         case STENCIL_INDEX8: return STENCIL_INDEX;
223         case DEPTH_COMPONENT16:
224         case DEPTH_COMPONENT24:
225         case DEPTH_COMPONENT32:
226         case DEPTH_COMPONENT32F: return DEPTH_COMPONENT;
227         default: throw invalid_argument("get_components");
228         }
229 }
230
231 PixelFormat get_default_sized_pixelformat(PixelComponents comp)
232 {
233         DataType type = UNSIGNED_BYTE;
234         if(comp==DEPTH_COMPONENT)
235         {
236                 if(get_gl_api()==OPENGL_ES2 && !ARB_depth_buffer_float)
237                         type = UNSIGNED_SHORT;
238                 else
239                         type = FLOAT;
240         }
241         return make_pixelformat(comp, type);
242 }
243
244 PixelFormat get_srgb_pixelformat(PixelFormat pf)
245 {
246         switch(pf)
247         {
248         case RGB8: return SRGB8;
249         case RGBA8: return SRGB8_ALPHA8;
250         default: return pf;
251         }
252 }
253
254 unsigned get_component_count(PixelComponents comp)
255 {
256         switch(comp)
257         {
258         case STENCIL_INDEX:
259         case DEPTH_COMPONENT:
260         case RED:
261         case LUMINANCE:
262                 return 1;
263         case RG:
264         case LUMINANCE_ALPHA:
265                 return 2;
266         case RGB:
267         case BGR:
268                 return 3;
269         case RGBA:
270         case BGRA:
271                 return 4;
272         default:
273                 throw invalid_argument("get_component_count");
274         }
275 }
276
277 DataType get_component_type(PixelFormat pf)
278 {
279         switch(pf)
280         {
281         case R8:
282         case RG8:
283         case RGB8:
284         case RGBA8:
285         case SRGB8:
286         case SRGB8_ALPHA8:
287         case LUMINANCE8:
288         case LUMINANCE8_ALPHA8:
289                 return UNSIGNED_BYTE;
290         case R16F:
291         case RG16F:
292         case RGB16F:
293         case RGBA16F:
294                 return HALF_FLOAT;
295         case DEPTH_COMPONENT16:
296                 return UNSIGNED_SHORT;
297         case R32F:
298         case RG32F:
299         case RGB32F:
300         case RGBA32F:
301         case DEPTH_COMPONENT32:
302                 return UNSIGNED_INT;
303         case DEPTH_COMPONENT32F:
304                 return FLOAT;
305         case DEPTH_COMPONENT24:
306                 // There's no DataType value with 24-bit size
307         default:
308                 throw invalid_argument("get_component_type");
309         }
310 }
311
312 unsigned get_pixel_size(PixelFormat pf)
313 {
314         return get_component_count(pf)*get_type_size(get_component_type(pf));
315 }
316
317 void require_pixelformat(PixelFormat pf)
318 {
319         /* TODO These checks are only accurate for textures.  On OpenGL ES some
320         formats are allowed for render buffers earlier than textures.  In particular
321         it's possible to create a 16-bit depth renderbuffer on OpenGL ES 2.0 but
322         depth textures are only available with 3.0 or the OES_depth_texture
323         extension.*/
324         switch(pf)
325         {
326         case RGB8:
327         case RGBA8:
328                 { static Require _req(OES_required_internalformat); }
329                 break;
330         case R8:
331         case RG8:
332                 { static Require _req(ARB_texture_rg); }
333                 break;
334         case R16F:
335         case R32F:
336         case RG16F:
337         case RG32F:
338                 { static Require _req(ARB_texture_rg); }
339                 { static Require _req(ARB_texture_float); }
340                 break;
341         case RGB16F:
342         case RGB32F:
343         case RGBA16F:
344         case RGBA32F:
345                 { static Require _req(ARB_texture_float); }
346                 break;
347         case SRGB8:
348         case SRGB8_ALPHA8:
349                 { static Require _req(EXT_texture_sRGB); }
350                 break;
351         case DEPTH_COMPONENT16:
352         case DEPTH_COMPONENT24:
353         case DEPTH_COMPONENT32:
354                 { static Require _req(ARB_depth_texture); }
355                 { static Require _req(OES_required_internalformat); }
356                 break;
357         case DEPTH_COMPONENT32F:
358                 { static Require _req(ARB_depth_buffer_float); }
359                 break;
360         case STENCIL_INDEX8:
361                 { static Require _req(OES_texture_stencil8); }
362                 break;
363         default:
364                 throw invalid_argument("require_pixelformat");
365         }
366 }
367
368 } // namespace GL
369 } // namespace Msp