X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?a=blobdiff_plain;ds=sidebyside;f=src%2F3dengfx%2Fsrc%2Fgfx%2Fimg_manip.cpp;fp=src%2F3dengfx%2Fsrc%2Fgfx%2Fimg_manip.cpp;h=9a9e7ccbee7072b3d9fc02119e7b7d1735ddff63;hb=6e23259dbabaeb1711a2a5ca25b9cb421f693759;hp=0000000000000000000000000000000000000000;hpb=fe068fa879814784c45e0cb2e65dac489e8f5594;p=summerhack diff --git a/src/3dengfx/src/gfx/img_manip.cpp b/src/3dengfx/src/gfx/img_manip.cpp new file mode 100644 index 0000000..9a9e7cc --- /dev/null +++ b/src/3dengfx/src/gfx/img_manip.cpp @@ -0,0 +1,579 @@ +/* +Copyright 2004 John Tsiombikas + +This file is part of the 3dengfx, realtime visualization system. + +3dengfx is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +3dengfx is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with 3dengfx; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* image manipulation + * author: Mihalis Georgoulopoulos 2004 + * modified: John Tsiombikas 2004 + */ + +#include +#include +#include +#include +#include +#include "img_manip.hpp" +#include "color.hpp" +#include "common/err_msg.h" + +// Macros +#define PACK_ARGB32(a,r,g,b) PACK_COLOR32(a,r,g,b) + +#define GETA(c) (((c) >> ALPHA_SHIFT32) & ALPHA_MASK32) +#define GETR(c) (((c) >> RED_SHIFT32) & RED_MASK32) +#define GETG(c) (((c) >> GREEN_SHIFT32) & GREEN_MASK32) +#define GETB(c) (((c) >> BLUE_SHIFT32) & BLUE_MASK32) + +static inline scalar_t cerp(scalar_t x0, scalar_t x1, scalar_t x2, scalar_t x3, scalar_t t); +static inline int clamp_integer(int i, int from, int to); + +// ------------ simple operations ---------------- +void clear_pixel_buffer(PixelBuffer *pb, const Color &col) { + int sz = pb->width * pb->height; + Pixel pcol = pack_color32(col); + Pixel *ptr = pb->buffer; + + for(int i=0; i= src_width) i2 = src_width - 1; + i3 = i1 + 2; if(i3 >= src_width) i3 = src_width - 1; + + x0 = src[i0 * src_pitch]; + x1 = src[i1 * src_pitch]; + x2 = src[i2 * src_pitch]; + x3 = src[i3 * src_pitch]; + + t = ((scalar_t)i * (scalar_t)src_width) / (scalar_t)dst_width; + t -= i1; + + // write the destination element + dst[i * dst_pitch] = cerp(x0, x1, x2, x3, t); + } + + return true; +} + +static bool resample2d(scalar_t *dst, int dst_w, int dst_h, scalar_t *src, int src_w, int src_h) +{ + if (!src || !dst) return false; + + if (dst_w == src_w && dst_h == src_h) + { + memcpy(dst, src, dst_w * dst_h * sizeof(scalar_t)); + return true; + } + + // first resample along x + scalar_t *temp = (scalar_t*)malloc(dst_w * src_h * sizeof(scalar_t)); + + if (dst_w == src_w) + { + memcpy(temp, src, src_w * src_h * sizeof(scalar_t)); + } + else + { + // horizontal resample + for (int i=0;ibuffer || pb->width < 0 || pb->height < 0) return false; + + if ((int)pb->width == w && (int)pb->height == h) return true; + + // split channels + scalar_t *a, *newa, *r, *newr, *g, *newg, *b, *newb; + + a = (scalar_t*)malloc(pb->width * pb->height * sizeof(scalar_t)); + r = (scalar_t*)malloc(pb->width * pb->height * sizeof(scalar_t)); + g = (scalar_t*)malloc(pb->width * pb->height * sizeof(scalar_t)); + b = (scalar_t*)malloc(pb->width * pb->height * sizeof(scalar_t)); + + newa = (scalar_t*)malloc(w * h * sizeof(scalar_t)); + newr = (scalar_t*)malloc(w * h * sizeof(scalar_t)); + newg = (scalar_t*)malloc(w * h * sizeof(scalar_t)); + newb = (scalar_t*)malloc(w * h * sizeof(scalar_t)); + + for(int i=0; i<(int)(pb->width * pb->height); i++) + { + a[i] = GETA(pb->buffer[i]); + r[i] = GETR(pb->buffer[i]); + g[i] = GETG(pb->buffer[i]); + b[i] = GETB(pb->buffer[i]); + } + + // resample + resample2d(newa, w, h, a, pb->width, pb->height); + resample2d(newr, w, h, r, pb->width, pb->height); + resample2d(newg, w, h, g, pb->width, pb->height); + resample2d(newb, w, h, b, pb->width, pb->height); + + // pack + Pixel *temp = (Pixel*)malloc(w * h * sizeof(Pixel)); + pack_scalar_rgb2dw(temp, newa, newr, newg, newb, w * h); + free(pb->buffer); + pb->buffer = temp; + temp = 0; + pb->width = w; + pb->height = h; + + // cleanup + free(a); free(r); free(g); free(b); + free(newa); free(newr); free(newg); free(newb); + + return true; +} + + +// --- static inline functions --- + +static inline scalar_t cerp(scalar_t x0, scalar_t x1, scalar_t x2, scalar_t x3, scalar_t t) +{ + scalar_t a0, a1, a2, a3, t2; + + t2 = t * t; + a0 = x3 - x2 - x0 + x1; + a1 = x0 - x1 - a0; + a2 = x2 - x0; + a3 = x1; + + return(a0 * t * t2 + a1 * t2 + a2 * t + a3); +} + + +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#define CLAMP(n, l, h) MIN(MAX((n), (l)), (h)) + +static inline int clamp_integer(int i, int from, int to) +{ + return CLAMP(i, from, to); +} + +// Kernels +//---------------------------------------------------------------- + +static ImgSamplingMode samp_mode = SAMPLE_CLAMP; + +static inline int map_index(int c, int dim) +{ + + switch (samp_mode) + { + case SAMPLE_WRAP: + { + if (c < 0) + { + while(c < 0) c += dim; + return c; + } + if (c >= dim) return c % dim; + break; + } + case SAMPLE_MIRROR: + { + if (c < 0) return -c; + if (c >= dim) return dim - c - 1; + break; + } + + case SAMPLE_CLAMP: + default: + { + if (c < 0) return 0; + if (c >= dim) return dim - 1; + break; + } + } + + return c; +} + +static void split_channels(Pixel *img, Pixel *a, Pixel *r, Pixel *g, Pixel *b, unsigned int pixel_count) +{ + for(unsigned int i=0; ibuffer) return false; + if(pb->width <= 0 || pb->height <= 0) return false; + if(!(kernel_dim / 2)) return false; + + unsigned int sz = pb->width * pb->height; + + // set sampling mode + samp_mode = sampling; + + // allocate memory + Pixel *tempa = (Pixel*)malloc(sz * sizeof(Pixel)); + Pixel *tempr = (Pixel*)malloc(sz * sizeof(Pixel)); + Pixel *tempg = (Pixel*)malloc(sz * sizeof(Pixel)); + Pixel *tempb = (Pixel*)malloc(sz * sizeof(Pixel)); + + // split channels + split_channels(pb->buffer, tempa, tempr, tempg, tempb, sz); + + // apply kernel + Pixel *a = apply_kernel_to_channel(kernel, kernel_dim, tempa, pb->width, pb->height); + free(tempa); + + Pixel *r = apply_kernel_to_channel(kernel, kernel_dim, tempr, pb->width, pb->height); + free(tempr); + + Pixel *g = apply_kernel_to_channel(kernel, kernel_dim, tempg, pb->width, pb->height); + free(tempg); + + Pixel *b = apply_kernel_to_channel(kernel, kernel_dim, tempb, pb->width, pb->height); + free(tempb); + + // join channels + join_channels(pb->buffer, a, r, g, b, sz); + + free(a); + free(r); + free(g); + free(b); + + return true; +} + +int* load_kernel(const char* filename, int *dim) +{ + // try to open the file + FILE *input = fopen(filename, "r"); + + if (!input) return 0; + + fseek(input , 0 , SEEK_END); + int size = ftell(input); + fseek(input , 0 , SEEK_SET); + + // allocate memory + //char *s = (char*) malloc(size+1); + + char s[2048]; + + int i; + + for(i=0; ibuffer; + int sz = pb->width * pb->height; + + for(int i=0; i>= 1; + tempc2 &= 0x00ff00ff; tempc2 >>= 1; + tempc3 &= 0xff00ff00; tempc3 >>= 1; + tempc4 &= 0x00ff00ff; tempc4 >>= 1; + + tempc1 = (tempc1 + tempc3) & 0xff00ff00; + tempc2 = (tempc2 + tempc4) & 0x00ff00ff; + + return tempc1 | tempc2; +} + + +bool blur(PixelBuffer *pb, ImgSamplingMode sampling) +{ + if(!pb) return false; + if(pb->width <= 0 || pb->height <= 0) return false; + + samp_mode = sampling; + + Pixel *temp = (Pixel*)malloc(pb->width * pb->height * sizeof(Pixel)); + + Pixel *scanline = pb->buffer; + Pixel *dst_scanline = temp; + + // blur horizontally + for(unsigned int j=0; jheight; j++) + { + for(unsigned int i=0; iwidth; i++) + { + dst_scanline[i] = blur_pixels(scanline[map_index(i-1 , pb->width)], scanline[map_index(i+1 , pb->width)]); + } + scanline += pb->width; + dst_scanline += pb->width; + } + + // blur vertically + for(unsigned int i=0; iwidth; i++) + { + for(unsigned int j=0;jheight;j++) + { + pb->buffer[i+j*pb->width] = blur_pixels(temp[i+map_index(j-1,pb->height)*pb->width], temp[i+map_index(j+1,pb->height)*pb->width]); + } + } + + // cleanup + free(temp); + + return true; +}