fix_lightmap script
[laserbrain_demo] / 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 void Image::resize_half()
147 {
148         int pixsz = pixel_size(fmt);
149         int newxsz = width / 2;
150         int newysz = height / 2;
151
152         if(!newxsz || !newysz) return;
153
154         unsigned char *newpix = new unsigned char[newxsz * newysz * pixsz];
155
156         unsigned char *sptr = (unsigned char*)pixels;
157         unsigned char *dptr = newpix;
158
159         for(int i=0; i<newysz; i++) {
160                 if(i & 1) sptr += width * pixsz;
161                 for(int j=0; j<newxsz; j++) {
162                         memcpy(dptr, sptr, pixsz);
163                         dptr += pixsz;
164                         sptr += pixsz * 2;
165                 }
166         }
167
168         delete [] (char*)pixels;
169         pixels = newpix;
170         width = newxsz;
171         height = newysz;
172 }
173
174 bool Image::load(const char *fname)
175 {
176         struct img_pixmap pixmap;
177
178         img_init(&pixmap);
179         if(img_load(&pixmap, fname) == -1) {
180                 return false;
181         }
182
183         Format fmt;
184         switch(pixmap.fmt) {
185         case IMG_FMT_GREY8:
186                 fmt = FMT_GREY;
187                 break;
188         case IMG_FMT_RGB24:
189                 fmt = FMT_RGB;
190                 break;
191         case IMG_FMT_RGBA32:
192                 fmt = FMT_RGBA;
193                 break;
194         case IMG_FMT_GREYF:
195                 fmt = FMT_GREY_FLOAT;
196                 break;
197         case IMG_FMT_RGBF:
198                 fmt = FMT_RGB_FLOAT;
199                 break;
200         case IMG_FMT_RGBAF:
201                 fmt = FMT_RGBA_FLOAT;
202                 break;
203         default:
204                 img_destroy(&pixmap);
205                 return false;
206         }
207
208         if(!set_pixels(pixmap.width, pixmap.height, pixmap.pixels, fmt)) {
209                 img_destroy(&pixmap);
210                 return false;
211         }
212         img_destroy(&pixmap);
213         return true;
214 }
215
216 bool Image::save(const char *fname) const
217 {
218         struct img_pixmap pixmap;
219
220         img_init(&pixmap);
221
222         switch(fmt) {
223         case FMT_GREY:
224                 pixmap.fmt = IMG_FMT_GREY8;
225                 break;
226         case FMT_GREY_FLOAT:
227                 pixmap.fmt = IMG_FMT_GREYF;
228                 break;
229         case FMT_RGB:
230                 pixmap.fmt = IMG_FMT_RGB24;
231                 break;
232         case FMT_RGB_FLOAT:
233                 pixmap.fmt = IMG_FMT_RGBF;
234                 break;
235         case FMT_RGBA:
236                 pixmap.fmt = IMG_FMT_RGBA32;
237                 break;
238         case FMT_RGBA_FLOAT:
239                 pixmap.fmt = IMG_FMT_RGBAF;
240                 break;
241         default:
242                 return false;
243         }
244
245         pixmap.width = width;
246         pixmap.height = height;
247         pixmap.pixels = pixels;
248         pixmap.pixelsz = pixel_size(fmt);
249
250         if(img_save(&pixmap, fname) == -1) {
251                 return false;
252         }
253         return true;
254 }
255
256 static int pixel_elements(Image::Format fmt)
257 {
258         switch(fmt) {
259         case Image::FMT_GREY:
260         case Image::FMT_GREY_FLOAT:
261                 return 1;
262
263         case Image::FMT_RGB:
264         case Image::FMT_RGB_FLOAT:
265                 return 3;
266
267         case Image::FMT_RGBA:
268         case Image::FMT_RGBA_FLOAT:
269                 return 4;
270
271         default:
272                 break;
273         }
274         return 0;
275 }
276
277 static int elem_size(Image::Format fmt)
278 {
279         switch(fmt) {
280         case Image::FMT_GREY:
281         case Image::FMT_RGB:
282         case Image::FMT_RGBA:
283                 return 1;
284
285         case Image::FMT_GREY_FLOAT:
286         case Image::FMT_RGB_FLOAT:
287         case Image::FMT_RGBA_FLOAT:
288                 return sizeof(float);
289
290         default:
291                 break;
292         }
293         return 0;
294 }
295
296 static int pixel_size(Image::Format fmt)
297 {
298         return elem_size(fmt) * pixel_elements(fmt);
299 }