dbf-halloween2015

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