dbf-halloween2015

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