tavli

annotate src/image.cc @ 23:3e6430028d54

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