dbf-halloween2015

view src/image.cc @ 0:50683c78264e

initial commit
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 01 Nov 2015 00:09:12 +0200
parents
children c37fe5d8a4ed
line source
1 #include <string.h>
2 #include <stdlib.h>
3 #include <alloca.h>
4 #include "opengl.h"
5 #include "image.h"
6 #include "imago2.h"
9 static unsigned int next_pow2(unsigned int x);
11 Image::Image()
12 {
13 width = height = tex_width = tex_height = 0;
14 pixels = 0;
15 tex = 0;
16 tex_valid = false;
17 }
19 Image::~Image()
20 {
21 destroy();
22 }
24 Image::Image(const Image &img)
25 {
26 pixels = 0;
27 create(img.width, img.height, img.pixels);
28 }
30 Image &Image::operator =(const Image &img)
31 {
32 if(&img != this) {
33 create(img.width, img.height, img.pixels);
34 }
35 return *this;
36 }
38 bool Image::create(int width, int height, unsigned char *pixels)
39 {
40 destroy();
42 try {
43 unsigned char *tmp = new unsigned char[width * height * 4];
44 this->pixels = tmp;
45 this->width = width;
46 this->height = height;
47 }
48 catch(...) {
49 return false;
50 }
52 if(pixels) {
53 memcpy(this->pixels, pixels, width * height * 4);
54 }
55 return true;
56 }
58 void Image::destroy()
59 {
60 delete [] pixels;
61 pixels = 0;
62 width = height = 0;
64 if(tex) {
65 glDeleteTextures(1, &tex);
66 tex = 0;
67 tex_valid = false;
68 }
69 }
71 bool Image::load(const char *fname)
72 {
73 int xsz, ysz;
74 unsigned char *pix = (unsigned char*)img_load_pixels(fname, &xsz, &ysz, IMG_FMT_RGBA32);
75 if(!pix) {
76 return false;
77 }
78 return create(xsz, ysz, pix);
79 }
81 bool Image::save(const char *fname) const
82 {
83 return img_save_pixels(fname, pixels, width, height, IMG_FMT_RGBA32) != -1;
84 }
86 unsigned int Image::texture() const
87 {
88 if(!pixels) {
89 return 0;
90 }
91 if(!tex) {
92 glGenTextures(1, &tex);
93 }
95 if(!tex_valid) {
96 tex_width = next_pow2(width);
97 tex_height = next_pow2(height);
99 glBindTexture(GL_TEXTURE_2D, tex);
100 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
101 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
103 if(GLEW_SGIS_generate_mipmap) {
104 glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, 1);
106 void *data = (width == tex_width && height == tex_height) ? pixels : 0;
107 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex_width, tex_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
108 if(!data) {
109 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
110 }
111 } else {
112 gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, tex_width, tex_height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
113 }
115 if(GLEW_EXT_texture_filter_anisotropic) {
116 static float max_aniso = -1.0;
118 if(max_aniso < 0.0) {
119 glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &max_aniso);
120 printf("using anisotropic filtering: x%g\n", max_aniso);
121 }
123 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, max_aniso);
124 }
125 tex_valid = true;
126 }
127 return tex;
128 }
130 int Image::texture_width() const
131 {
132 return tex_width;
133 }
135 int Image::texture_height() const
136 {
137 return tex_height;
138 }
140 void Image::invalidate_texture()
141 {
142 tex_valid = false;
143 }
146 void clear_image(Image *img)
147 {
148 clear_image(img, 0, 0, 0, 255);
149 }
151 void clear_image(Image *img, float r, float g, float b, float a)
152 {
153 if(!img->pixels) {
154 return;
155 }
157 unsigned char col[4];
158 unsigned char *ptr = img->pixels;
159 int npix = img->width * img->height;
161 col[0] = (int)(r * 255.0);
162 col[1] = (int)(g * 255.0);
163 col[2] = (int)(b * 255.0);
164 col[3] = (int)(a * 255.0);
166 for(int i=0; i<npix; i++) {
167 for(int j=0; j<4; j++) {
168 ptr[j] = col[j];
169 }
170 ptr += 4;
171 }
172 }
174 void clear_image_alpha(Image *img, float a)
175 {
176 if(!img->pixels) {
177 return;
178 }
180 unsigned char alpha = (int)(a * 255.0);
181 unsigned char *ptr = img->pixels;
182 int npix = img->width * img->height;
184 for(int i=0; i<npix; i++) {
185 ptr[3] = alpha;
186 ptr += 4;
187 }
188 }
190 bool combine_image(Image *dest, const Image *aimg, const Image *bimg, ImgCombine op, float t)
191 {
192 int xsz = dest->width;
193 int ysz = dest->height;
194 int npixels = xsz * ysz;
195 int nbytes = npixels * 4;
196 int tint = (int)(t * 255);
198 if(aimg->width != xsz || bimg->width != xsz || aimg->height != ysz || bimg->height != ysz) {
199 return false;
200 }
202 unsigned char *dptr = dest->pixels;
203 const unsigned char *aptr = aimg->pixels;
204 const unsigned char *bptr = bimg->pixels;
206 switch(op) {
207 case IMG_OP_ADD:
208 for(int i=0; i<nbytes; i++) {
209 unsigned int x = *aptr++ + *bptr++;
210 *dptr++ = x > 255 ? 255 : x;
211 }
212 break;
214 case IMG_OP_SUB:
215 for(int i=0; i<nbytes; i++) {
216 int x = (int)*aptr++ - (int)*bptr++;
217 *dptr++ = x < 0 ? 0 : x;
218 }
219 break;
221 case IMG_OP_MUL:
222 for(int i=0; i<nbytes; i++) {
223 unsigned int x = ((unsigned int)*aptr++ * (unsigned int)*bptr++) >> 8;
224 *dptr++ = x > 255 ? 255 : x;
225 }
226 break;
228 case IMG_OP_LERP:
229 for(int i=0; i<nbytes; i++) {
230 int x = (int)*aptr + ((((int)*bptr - (int)*aptr) * tint) >> 8);
231 *dptr++ = x > 255 ? 255 : (x < 0 ? 0 : x);
232 }
233 break;
235 default:
236 break;
237 }
239 dest->invalidate_texture();
240 return true;
241 }
243 void convolve_horiz_image(Image *dest, float *kern, int ksz, float scale)
244 {
245 if((ksz & 1) == 0) {
246 fprintf(stderr, "%s: kernel size (%d) must be odd, skipping last value\n", __FUNCTION__, ksz);
247 --ksz;
248 }
249 if(scale == 0.0) {
250 // calculate scale factor
251 float sum = 0.0;
252 for(int i=0; i<ksz; i++) {
253 sum += kern[i];
254 }
255 scale = 1.0 / sum;
256 }
257 int krad = ksz / 2;
258 float *buf = (float*)alloca(dest->width * 4 * sizeof *buf);
259 unsigned char *sptr = dest->pixels;
261 for(int i=0; i<dest->height; i++) {
262 float *bptr = buf;
263 for(int j=0; j<dest->width * 4; j++) {
264 *bptr++ = (float)(sptr[j] / 255.0);
265 }
267 for(int j=0; j<dest->width; j++) {
268 float col[] = {0, 0, 0, 0};
270 for(int k=0; k<ksz; k++) {
271 int idx = j + k - krad;
272 if(idx < 0) idx = 0;
273 if(idx >= dest->width) idx = dest->width - 1;
275 col[0] += buf[idx * 4] * kern[k];
276 col[1] += buf[idx * 4 + 1] * kern[k];
277 col[2] += buf[idx * 4 + 2] * kern[k];
278 col[3] += buf[idx * 4 + 3] * kern[k];
279 }
281 int ri = (int)(col[0] * scale * 255.0);
282 int gi = (int)(col[1] * scale * 255.0);
283 int bi = (int)(col[2] * scale * 255.0);
284 int ai = (int)(col[3] * scale * 255.0);
286 sptr[0] = ri < 0 ? 0 : (ri > 255 ? 255 : ri);
287 sptr[1] = gi < 0 ? 0 : (gi > 255 ? 255 : gi);
288 sptr[2] = bi < 0 ? 0 : (bi > 255 ? 255 : bi);
289 sptr[3] = ai < 0 ? 0 : (ai > 255 ? 255 : ai);
290 sptr += 4;
291 }
292 }
294 dest->invalidate_texture();
295 }
297 void convolve_vert_image(Image *dest, float *kern, int ksz, float scale)
298 {
299 if((ksz & 1) == 0) {
300 fprintf(stderr, "%s: kernel size (%d) must be odd, skipping last value\n", __FUNCTION__, ksz);
301 --ksz;
302 }
303 if(scale == 0.0) {
304 // calculate scale factor
305 float sum = 0.0;
306 for(int i=0; i<ksz; i++) {
307 sum += kern[i];
308 }
309 scale = 1.0 / sum;
310 }
311 int krad = ksz / 2;
312 float *buf = (float*)alloca(dest->height * 4 * sizeof *buf);
313 unsigned char *sptr = dest->pixels;
315 for(int i=0; i<dest->width; i++) {
316 float *bptr = buf;
317 sptr = dest->pixels + i * 4;
319 for(int j=0; j<dest->height; j++) {
320 for(int k=0; k<4; k++) {
321 *bptr++ = (float)(sptr[k] / 255.0);
322 }
323 sptr += dest->width * 4;
324 }
326 sptr = dest->pixels + i * 4;
328 for(int j=0; j<dest->height; j++) {
329 float col[] = {0, 0, 0, 0};
331 for(int k=0; k<ksz; k++) {
332 int idx = j + k - krad;
333 if(idx < 0) idx = 0;
334 if(idx >= dest->height) idx = dest->height - 1;
336 col[0] += buf[idx * 4] * kern[k];
337 col[1] += buf[idx * 4 + 1] * kern[k];
338 col[2] += buf[idx * 4 + 2] * kern[k];
339 col[3] += buf[idx * 4 + 3] * kern[k];
340 }
342 int ri = (int)(col[0] * scale * 255.0);
343 int gi = (int)(col[1] * scale * 255.0);
344 int bi = (int)(col[2] * scale * 255.0);
345 int ai = (int)(col[3] * scale * 255.0);
347 sptr[0] = ri < 0 ? 0 : (ri > 255 ? 255 : ri);
348 sptr[1] = gi < 0 ? 0 : (gi > 255 ? 255 : gi);
349 sptr[2] = bi < 0 ? 0 : (bi > 255 ? 255 : bi);
350 sptr[3] = ai < 0 ? 0 : (ai > 255 ? 255 : ai);
351 sptr += dest->width * 4;
352 }
353 }
354 }
356 static unsigned int next_pow2(unsigned int x)
357 {
358 x--;
359 x = (x >> 1) | x;
360 x = (x >> 2) | x;
361 x = (x >> 4) | x;
362 x = (x >> 8) | x;
363 x = (x >> 16) | x;
364 return x + 1;
365 }