shadows, textures, resource managers... shaders...
[antikythera] / src / image.cc
1 #include <string.h>
2
3 #ifndef _MSC_VER
4 #include <alloca.h>
5 #else
6 #include <malloc.h>
7 #endif
8
9 #include "imago2.h"
10 #include "image.h"
11
12 static int pixel_elements(Image::Format fmt);
13 static int elem_size(Image::Format fmt);
14 static int pixel_size(Image::Format fmt);
15
16 Image::Image()
17 {
18         fmt = FMT_RGBA;
19         width = height = 0;
20         pixels = 0;
21 }
22
23 Image::~Image()
24 {
25         delete [] (char*)pixels;
26 }
27
28 int Image::get_width() const
29 {
30         return width;
31 }
32
33 int Image::get_height() const
34 {
35         return height;
36 }
37
38 Image::Format Image::get_format() const
39 {
40         return fmt;
41 }
42
43 bool Image::create(int x, int y, Format fmt)
44 {
45         width = x;
46         height = y;
47         this->fmt = fmt;
48
49         try {
50                 pixels = new char[x * y * pixel_size(fmt)];
51         }
52         catch(...) {
53                 return false;
54         }
55         return true;
56 }
57
58 bool Image::set_pixels(int xsz, int ysz, void *pixels, Format fmt)
59 {
60         if(!create(xsz, ysz, fmt)) {
61                 return false;
62         }
63         memcpy(this->pixels, pixels, xsz * ysz * pixel_size(fmt));
64         return true;
65 }
66
67 bool Image::set_pixels(int xsz, int ysz, void *pixels, int scan_width, Format fmt)
68 {
69         return set_pixels(xsz, ysz, pixels, 0, 0, scan_width, fmt);
70 }
71
72 bool Image::set_pixels(int xsz, int ysz, void *pixels, int x, int y, int scan_width, Format fmt)
73 {
74         if(scan_width <= 0) {
75                 scan_width = xsz;
76         }
77
78         if(!create(xsz, ysz, fmt)) {
79                 return false;
80         }
81
82         int pixsz = pixel_size(fmt);
83
84         unsigned char *dest = (unsigned char*)this->pixels;
85         unsigned char *src = (unsigned char*)pixels + (y * scan_width + x) * pixsz;
86         for(int i=0; i<ysz; i++) {
87                 memcpy(dest, src, xsz * pixsz);
88                 dest += xsz * pixsz;
89                 src += scan_width * pixsz;
90         }
91         return true;
92 }
93
94 void *Image::get_pixels() const
95 {
96         return pixels;
97 }
98
99 void Image::flip_horizontal()
100 {
101         int pixsz = pixel_size(fmt);
102
103         unsigned char *tmppix = (unsigned char*)alloca(pixsz);
104
105         unsigned char *scan = (unsigned char*)pixels;
106         for(int i=0; i<height; i++) {
107                 unsigned char *dest = scan;
108                 unsigned char *src = scan + (width - 1) * pixsz;
109
110                 while(src > dest) {
111                         memcpy(tmppix, src, pixsz);
112                         memcpy(src, dest, pixsz);
113                         memcpy(dest, tmppix, pixsz);
114                         dest += pixsz;
115                         src -= pixsz;
116                 }
117
118                 scan += width * pixsz;
119         }
120 }
121
122 void Image::flip_vertical()
123 {
124         int pixsz = pixel_size(fmt);
125
126         unsigned char *tmpscan = (unsigned char*)alloca(width * pixsz);
127
128         unsigned char *dest = (unsigned char*)pixels;
129         unsigned char *src = (unsigned char*)pixels + (height - 1) * width * pixsz;
130
131         while(src > dest) {
132                 memcpy(tmpscan, src, width * pixsz);
133                 memcpy(src, dest, width * pixsz);
134                 memcpy(dest, tmpscan, width * pixsz);
135                 dest += width * pixsz;
136                 src -= width * pixsz;
137         }
138 }
139
140 void Image::rotate_180()
141 {
142         flip_vertical();
143         flip_horizontal();
144 }
145
146 bool Image::load(const char *fname)
147 {
148         struct img_pixmap pixmap;
149
150         img_init(&pixmap);
151         if(img_load(&pixmap, fname) == -1) {
152                 return false;
153         }
154
155         Format fmt;
156         switch(pixmap.fmt) {
157         case IMG_FMT_GREY8:
158                 fmt = FMT_GREY;
159                 break;
160         case IMG_FMT_RGB24:
161                 fmt = FMT_RGB;
162                 break;
163         case IMG_FMT_RGBA32:
164                 fmt = FMT_RGBA;
165                 break;
166         case IMG_FMT_GREYF:
167                 fmt = FMT_GREY_FLOAT;
168                 break;
169         case IMG_FMT_RGBF:
170                 fmt = FMT_RGB_FLOAT;
171                 break;
172         case IMG_FMT_RGBAF:
173                 fmt = FMT_RGBA_FLOAT;
174                 break;
175         default:
176                 img_destroy(&pixmap);
177                 return false;
178         }
179
180         if(!set_pixels(pixmap.width, pixmap.height, pixmap.pixels, fmt)) {
181                 img_destroy(&pixmap);
182                 return false;
183         }
184         img_destroy(&pixmap);
185         return true;
186 }
187
188 bool Image::save(const char *fname) const
189 {
190         struct img_pixmap pixmap;
191
192         img_init(&pixmap);
193
194         switch(fmt) {
195         case FMT_GREY:
196                 pixmap.fmt = IMG_FMT_GREY8;
197                 break;
198         case FMT_GREY_FLOAT:
199                 pixmap.fmt = IMG_FMT_GREYF;
200                 break;
201         case FMT_RGB:
202                 pixmap.fmt = IMG_FMT_RGB24;
203                 break;
204         case FMT_RGB_FLOAT:
205                 pixmap.fmt = IMG_FMT_RGBF;
206                 break;
207         case FMT_RGBA:
208                 pixmap.fmt = IMG_FMT_RGBA32;
209                 break;
210         case FMT_RGBA_FLOAT:
211                 pixmap.fmt = IMG_FMT_RGBAF;
212                 break;
213         default:
214                 return false;
215         }
216
217         pixmap.width = width;
218         pixmap.height = height;
219         pixmap.pixels = pixels;
220         pixmap.pixelsz = pixel_size(fmt);
221
222         if(img_save(&pixmap, fname) == -1) {
223                 return false;
224         }
225         return true;
226 }
227
228 static int pixel_elements(Image::Format fmt)
229 {
230         switch(fmt) {
231         case Image::FMT_GREY:
232         case Image::FMT_GREY_FLOAT:
233                 return 1;
234
235         case Image::FMT_RGB:
236         case Image::FMT_RGB_FLOAT:
237                 return 3;
238
239         case Image::FMT_RGBA:
240         case Image::FMT_RGBA_FLOAT:
241                 return 4;
242
243         default:
244                 break;
245         }
246         return 0;
247 }
248
249 static int elem_size(Image::Format fmt)
250 {
251         switch(fmt) {
252         case Image::FMT_GREY:
253         case Image::FMT_RGB:
254         case Image::FMT_RGBA:
255                 return 1;
256
257         case Image::FMT_GREY_FLOAT:
258         case Image::FMT_RGB_FLOAT:
259         case Image::FMT_RGBA_FLOAT:
260                 return sizeof(float);
261
262         default:
263                 break;
264         }
265         return 0;
266 }
267
268 static int pixel_size(Image::Format fmt)
269 {
270         return elem_size(fmt) * pixel_elements(fmt);
271 }