dbf-halloween2015

view src/image.cc @ 3:c37fe5d8a4ed

windows port
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 01 Nov 2015 06:04:28 +0200
parents 50683c78264e
children
line source
1 #include <string.h>
2 #include <stdlib.h>
3 #ifdef _MSC_VER
4 #include <malloc.h>
5 #else
6 #include <alloca.h>
7 #endif
8 #include "opengl.h"
9 #include "image.h"
10 #include "imago2.h"
13 static unsigned int next_pow2(unsigned int x);
15 Image::Image()
16 {
17 width = height = tex_width = tex_height = 0;
18 pixels = 0;
19 tex = 0;
20 tex_valid = false;
21 }
23 Image::~Image()
24 {
25 destroy();
26 }
28 Image::Image(const Image &img)
29 {
30 pixels = 0;
31 create(img.width, img.height, img.pixels);
32 }
34 Image &Image::operator =(const Image &img)
35 {
36 if(&img != this) {
37 create(img.width, img.height, img.pixels);
38 }
39 return *this;
40 }
42 bool Image::create(int width, int height, unsigned char *pixels)
43 {
44 destroy();
46 try {
47 unsigned char *tmp = new unsigned char[width * height * 4];
48 this->pixels = tmp;
49 this->width = width;
50 this->height = height;
51 }
52 catch(...) {
53 return false;
54 }
56 if(pixels) {
57 memcpy(this->pixels, pixels, width * height * 4);
58 }
59 return true;
60 }
62 void Image::destroy()
63 {
64 delete [] pixels;
65 pixels = 0;
66 width = height = 0;
68 if(tex) {
69 glDeleteTextures(1, &tex);
70 tex = 0;
71 tex_valid = false;
72 }
73 }
75 bool Image::load(const char *fname)
76 {
77 int xsz, ysz;
78 unsigned char *pix = (unsigned char*)img_load_pixels(fname, &xsz, &ysz, IMG_FMT_RGBA32);
79 if(!pix) {
80 return false;
81 }
82 return create(xsz, ysz, pix);
83 }
85 bool Image::save(const char *fname) const
86 {
87 return img_save_pixels(fname, pixels, width, height, IMG_FMT_RGBA32) != -1;
88 }
90 unsigned int Image::texture() const
91 {
92 if(!pixels) {
93 return 0;
94 }
95 if(!tex) {
96 glGenTextures(1, &tex);
97 }
99 if(!tex_valid) {
100 tex_width = next_pow2(width);
101 tex_height = next_pow2(height);
103 glBindTexture(GL_TEXTURE_2D, tex);
104 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
105 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
107 if(GLEW_SGIS_generate_mipmap) {
108 glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, 1);
110 void *data = (width == tex_width && height == tex_height) ? pixels : 0;
111 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex_width, tex_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
112 if(!data) {
113 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
114 }
115 } else {
116 gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, tex_width, tex_height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
117 }
119 if(GLEW_EXT_texture_filter_anisotropic) {
120 static float max_aniso = -1.0;
122 if(max_aniso < 0.0) {
123 glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &max_aniso);
124 printf("using anisotropic filtering: x%g\n", max_aniso);
125 }
127 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, max_aniso);
128 }
129 tex_valid = true;
130 }
131 return tex;
132 }
134 int Image::texture_width() const
135 {
136 return tex_width;
137 }
139 int Image::texture_height() const
140 {
141 return tex_height;
142 }
144 void Image::invalidate_texture()
145 {
146 tex_valid = false;
147 }
150 void clear_image(Image *img)
151 {
152 clear_image(img, 0, 0, 0, 255);
153 }
155 void clear_image(Image *img, float r, float g, float b, float a)
156 {
157 if(!img->pixels) {
158 return;
159 }
161 unsigned char col[4];
162 unsigned char *ptr = img->pixels;
163 int npix = img->width * img->height;
165 col[0] = (int)(r * 255.0);
166 col[1] = (int)(g * 255.0);
167 col[2] = (int)(b * 255.0);
168 col[3] = (int)(a * 255.0);
170 for(int i=0; i<npix; i++) {
171 for(int j=0; j<4; j++) {
172 ptr[j] = col[j];
173 }
174 ptr += 4;
175 }
176 }
178 void clear_image_alpha(Image *img, float a)
179 {
180 if(!img->pixels) {
181 return;
182 }
184 unsigned char alpha = (int)(a * 255.0);
185 unsigned char *ptr = img->pixels;
186 int npix = img->width * img->height;
188 for(int i=0; i<npix; i++) {
189 ptr[3] = alpha;
190 ptr += 4;
191 }
192 }
194 bool combine_image(Image *dest, const Image *aimg, const Image *bimg, ImgCombine op, float t)
195 {
196 int xsz = dest->width;
197 int ysz = dest->height;
198 int npixels = xsz * ysz;
199 int nbytes = npixels * 4;
200 int tint = (int)(t * 255);
202 if(aimg->width != xsz || bimg->width != xsz || aimg->height != ysz || bimg->height != ysz) {
203 return false;
204 }
206 unsigned char *dptr = dest->pixels;
207 const unsigned char *aptr = aimg->pixels;
208 const unsigned char *bptr = bimg->pixels;
210 switch(op) {
211 case IMG_OP_ADD:
212 for(int i=0; i<nbytes; i++) {
213 unsigned int x = *aptr++ + *bptr++;
214 *dptr++ = x > 255 ? 255 : x;
215 }
216 break;
218 case IMG_OP_SUB:
219 for(int i=0; i<nbytes; i++) {
220 int x = (int)*aptr++ - (int)*bptr++;
221 *dptr++ = x < 0 ? 0 : x;
222 }
223 break;
225 case IMG_OP_MUL:
226 for(int i=0; i<nbytes; i++) {
227 unsigned int x = ((unsigned int)*aptr++ * (unsigned int)*bptr++) >> 8;
228 *dptr++ = x > 255 ? 255 : x;
229 }
230 break;
232 case IMG_OP_LERP:
233 for(int i=0; i<nbytes; i++) {
234 int x = (int)*aptr + ((((int)*bptr - (int)*aptr) * tint) >> 8);
235 *dptr++ = x > 255 ? 255 : (x < 0 ? 0 : x);
236 }
237 break;
239 default:
240 break;
241 }
243 dest->invalidate_texture();
244 return true;
245 }
247 void convolve_horiz_image(Image *dest, float *kern, int ksz, float scale)
248 {
249 if((ksz & 1) == 0) {
250 fprintf(stderr, "%s: kernel size (%d) must be odd, skipping last value\n", __FUNCTION__, ksz);
251 --ksz;
252 }
253 if(scale == 0.0) {
254 // calculate scale factor
255 float sum = 0.0;
256 for(int i=0; i<ksz; i++) {
257 sum += kern[i];
258 }
259 scale = 1.0 / sum;
260 }
261 int krad = ksz / 2;
262 float *buf = (float*)alloca(dest->width * 4 * sizeof *buf);
263 unsigned char *sptr = dest->pixels;
265 for(int i=0; i<dest->height; i++) {
266 float *bptr = buf;
267 for(int j=0; j<dest->width * 4; j++) {
268 *bptr++ = (float)(sptr[j] / 255.0);
269 }
271 for(int j=0; j<dest->width; j++) {
272 float col[] = {0, 0, 0, 0};
274 for(int k=0; k<ksz; k++) {
275 int idx = j + k - krad;
276 if(idx < 0) idx = 0;
277 if(idx >= dest->width) idx = dest->width - 1;
279 col[0] += buf[idx * 4] * kern[k];
280 col[1] += buf[idx * 4 + 1] * kern[k];
281 col[2] += buf[idx * 4 + 2] * kern[k];
282 col[3] += buf[idx * 4 + 3] * kern[k];
283 }
285 int ri = (int)(col[0] * scale * 255.0);
286 int gi = (int)(col[1] * scale * 255.0);
287 int bi = (int)(col[2] * scale * 255.0);
288 int ai = (int)(col[3] * scale * 255.0);
290 sptr[0] = ri < 0 ? 0 : (ri > 255 ? 255 : ri);
291 sptr[1] = gi < 0 ? 0 : (gi > 255 ? 255 : gi);
292 sptr[2] = bi < 0 ? 0 : (bi > 255 ? 255 : bi);
293 sptr[3] = ai < 0 ? 0 : (ai > 255 ? 255 : ai);
294 sptr += 4;
295 }
296 }
298 dest->invalidate_texture();
299 }
301 void convolve_vert_image(Image *dest, float *kern, int ksz, float scale)
302 {
303 if((ksz & 1) == 0) {
304 fprintf(stderr, "%s: kernel size (%d) must be odd, skipping last value\n", __FUNCTION__, ksz);
305 --ksz;
306 }
307 if(scale == 0.0) {
308 // calculate scale factor
309 float sum = 0.0;
310 for(int i=0; i<ksz; i++) {
311 sum += kern[i];
312 }
313 scale = 1.0 / sum;
314 }
315 int krad = ksz / 2;
316 float *buf = (float*)alloca(dest->height * 4 * sizeof *buf);
317 unsigned char *sptr = dest->pixels;
319 for(int i=0; i<dest->width; i++) {
320 float *bptr = buf;
321 sptr = dest->pixels + i * 4;
323 for(int j=0; j<dest->height; j++) {
324 for(int k=0; k<4; k++) {
325 *bptr++ = (float)(sptr[k] / 255.0);
326 }
327 sptr += dest->width * 4;
328 }
330 sptr = dest->pixels + i * 4;
332 for(int j=0; j<dest->height; j++) {
333 float col[] = {0, 0, 0, 0};
335 for(int k=0; k<ksz; k++) {
336 int idx = j + k - krad;
337 if(idx < 0) idx = 0;
338 if(idx >= dest->height) idx = dest->height - 1;
340 col[0] += buf[idx * 4] * kern[k];
341 col[1] += buf[idx * 4 + 1] * kern[k];
342 col[2] += buf[idx * 4 + 2] * kern[k];
343 col[3] += buf[idx * 4 + 3] * kern[k];
344 }
346 int ri = (int)(col[0] * scale * 255.0);
347 int gi = (int)(col[1] * scale * 255.0);
348 int bi = (int)(col[2] * scale * 255.0);
349 int ai = (int)(col[3] * scale * 255.0);
351 sptr[0] = ri < 0 ? 0 : (ri > 255 ? 255 : ri);
352 sptr[1] = gi < 0 ? 0 : (gi > 255 ? 255 : gi);
353 sptr[2] = bi < 0 ? 0 : (bi > 255 ? 255 : bi);
354 sptr[3] = ai < 0 ? 0 : (ai > 255 ? 255 : ai);
355 sptr += dest->width * 4;
356 }
357 }
358 }
360 static unsigned int next_pow2(unsigned int x)
361 {
362 x--;
363 x = (x >> 1) | x;
364 x = (x >> 2) | x;
365 x = (x >> 4) | x;
366 x = (x >> 8) | x;
367 x = (x >> 16) | x;
368 return x + 1;
369 }