//------------------------------------------------- // // Generic Image Resize code. // // Used to refractalize the terrain. // // Based on Graphics Gems III General Filtered Image Rescaling // //---------------------------------------------------------------------------// // Copyright (C) Microsoft Corporation. All rights reserved. // //===========================================================================// #ifndef RESIZEIMAGE_H #define RESIZEIMAGE_H #ifndef DSTD_H #include "dstd.h" #endif #include #include #include #define BLACK_PIXEL 0.0f #define WHITE_PIXEL 255.0f #define RESIZE_PI 3.1415926 float CLAMP (float x, float min, float max) { if (x < min) return min; if (x > max) return max; return x; } typedef struct { long xSize; long ySize; float *data; } Image; float getPixel (Image *image, long x, long y) { if ((x < 0) || (x >= image->xSize) || (y < 0) || (y > image->ySize)) return 0.0f; float *p = image->data + (y*image->xSize); return p[x]; } void getRow (float *row, Image *image, long y) { if ((y < 0) || (y >= image->ySize)) return; memcpy(row,image->data + (y * image->xSize), image->ySize * sizeof(float)); } void getCol (float *col, Image *image, long x) { if ((x < 0) || (x >= image->xSize)) return; for (long i=0;iySize;i++) { *col = image->data[x + (i * image->xSize)]; col++; } } float putPixel (Image *image, long x, long y, float data) { if ((x < 0) || (x >= image->xSize) || (y < 0) || (y >= image->ySize)) return 0.0f; float *p = image->data + (y*image->xSize); return (p[x] = data); } //Filters #define filterSupport (1.0) #define boxSupport (0.5) #define triangleSupport (1.0) #define bellSupport (1.5) #define bSplineSupport (2.0) #define Lanczos3Support (3.0) #define MitchellSupport (2.0) double filter (double t) { if (t < 0.0) t = -t; if (t < 1.0) return((2.0 * t - 3.0) * t * t + 1.0); return 0.0; } double boxFilter (double t) { if ((t > -0.5) && (t <= 0.5)) return 1.0; return 0.0; } double triangleFilter (double t) { if (t < 0.0) t = -t; if (t < 1.0) return (1.0 - t); return 0.0; } double bellFilter (double t) { if (t < 0.0) t = -t; if (t < 0.5) return (0.75 - (t*t)); if (t < 1.5) { t = (t - 1.5); return (0.5 * (t*t)); } return 0.0; } double bSplineFilter (double t) { double tt; if (t < 0.0) t = -t; if (t < 1.0) { tt = t * t; return ((0.5 * tt * t) - tt + (2.0/3.0)); } else if (t < 2.0) { t = 2.0 - t; return ((1.0 / 6.0) * (t * t * t)); } return 0.0; } double sinc (double t) { t *= RESIZE_PI; if (t != 0.0) return (sin(t) / t); return 1.0; } double lanczos3Filter (double t) { if (t < 0.0) t = -t; if (t < 3.0) return (sinc(t) * sinc(t/3.0)); return 0.0; } double mitchellFilter (double t) { double B = (1.0 / 3.0); double C = (1.0 / 3.0); double tt; tt = t * t; if (t < 0.0) t = -t; if (t < 1.0) { t = (((12.0 - 9.0 * B - 6.0 * C) * (t * tt)) + ((-18.0 + 12.0 * B + 6.0 * C) * tt) + (6.0 - 2.0 * B)); return (t / 6.0); } else if (t < 2.0) { t = (((-1.0 * B - 6.0 * C) * (t * tt)) + ((6.0 * B + 30.0 * C) * tt) + ((-12.0 * B - 48.0 * C) * t) + (8.0 * B + 24.0 * C)); return (t / 6.0); } return 0.0; } typedef struct { long pixel; double weight; } CONTRIB; typedef struct { long n; CONTRIB *p; } CLIST; CLIST *contrib; Image *newImage(long xSize, long ySize) { Image *image = (Image *)malloc(sizeof(Image)); if (image) { image->data = (float *)malloc(sizeof(float) * xSize * ySize); memset(image->data,0,sizeof(float) * xSize * ySize); image->xSize = xSize; image->ySize = ySize; } return image; } void freeImage (Image *image) { free(image->data); free(image); } void zoom (Image *dst, Image *src, double (*filter)(double t), double fwidth) { Image *tmp; double xscale, yscale; long i,j,k; long n; double center, left, right; double width, fscale, weight; float *raster; //Create Intermediate image to hold horizontal zoom tmp = newImage(dst->xSize,src->ySize); xscale = (double)dst->xSize / (double)src->xSize; yscale = (double)dst->ySize / (double)src->ySize; //pre-calculate filter contributions for a row contrib = (CLIST *)malloc(dst->xSize * sizeof(CLIST)); memset(contrib,0,dst->xSize * sizeof(CLIST)); if (xscale < 1.0) { width = fwidth / xscale; fscale = 1.0 / xscale; for (i=0;ixSize;++i) { contrib[i].n = 0; contrib[i].p = (CONTRIB *)malloc((width * 2 + 1) * sizeof(CONTRIB)); center = (double)i / xscale; left = ceil(center - width); right = floor(center + width); for (j=left;j<=right;++j) { weight = center - (double)j; weight = (*filter)(weight / fscale) / fscale; if (j < 0) { n = -j; } else if (j >= src->xSize) { n = (src->xSize - j) + src->xSize - 1; } else { n = j; } k = contrib[i].n++; contrib[i].p[k].pixel = n; contrib[i].p[k].weight = weight; } } } else { for (i=0;ixSize;++i) { contrib[i].n = 0; contrib[i].p = (CONTRIB *)malloc((fwidth * 2 + 1) * sizeof(CONTRIB)); center = (double)i / xscale; left = ceil(center - fwidth); right = floor(center + fwidth); for (j=left;j<=right;++j) { weight = center - (double)j; weight = (*filter)(weight); if (j < 0) { n = -j; } else if (j >= src->xSize) { n = (src->xSize - j) + src->xSize - 1; } else { n = j; } k = contrib[i].n++; contrib[i].p[k].pixel = n; contrib[i].p[k].weight = weight; } } } //Apply filter to zoom horizontally from src to tmp raster = (float *)malloc(src->xSize * sizeof(float)); memset(raster,0,src->xSize * sizeof(float)); for (k=0;kySize; ++k) { getRow(raster,src, k); for (i=0;ixSize;++i) { weight = 0.0; for (j=0;jxSize; ++i) { free(contrib[i].p); contrib[i].p = NULL; } free(contrib); contrib = NULL; //pre-calculate filter contributions for horizontal filter weights contrib = (CLIST *)malloc(dst->ySize * sizeof(CLIST)); memset(contrib,0,dst->ySize * sizeof(CLIST)); if (yscale < 1.0) { width = fwidth / yscale; fscale = 1.0 / yscale; for (i=0;iySize;++i) { contrib[i].n = 0; contrib[i].p = (CONTRIB *)malloc((width * 2 + 1) * sizeof(CONTRIB)); center = (double)i / yscale; left = ceil(center - width); right = floor(center + width); for (j=left;j<=right;++j) { weight = center - (double)j; weight = (*filter)(weight / fscale) / fscale; if (j < 0) { n = -j; } else if (j >= tmp->ySize) { n = (tmp->ySize - j) + tmp->ySize - 1; } else { n = j; } k = contrib[i].n++; contrib[i].p[k].pixel = n; contrib[i].p[k].weight = weight; } } } else { for (i=0;iySize;++i) { contrib[i].n = 0; contrib[i].p = (CONTRIB *)malloc((fwidth * 2 + 1) * sizeof(CONTRIB)); center = (double)i / yscale; left = ceil(center - fwidth); right = floor(center + fwidth); for (j=left;j<=right;++j) { weight = center - (double)j; weight = (*filter)(weight); if (j < 0) { n = -j; } else if (j >= tmp->ySize) { n = (tmp->ySize - j) + tmp->ySize - 1; } else { n = j; } k = contrib[i].n++; contrib[i].p[k].pixel = n; contrib[i].p[k].weight = weight; } } } //Apply filter to zoom vertically from tmp to dst raster = (float *)malloc(sizeof(float) * tmp->ySize); memset(raster,0,sizeof(float) * tmp->ySize); for (k=0;kxSize;++k) { getCol(raster,tmp,k); for (i=0;iySize;++i) { weight = 0.0; for (j=0;jySize; ++i) { free(contrib[i].p); contrib[i].p = NULL; } free(contrib); contrib = NULL; freeImage(tmp); } void rescaleMap (float *dst, float *src, long dstSize, long srcSize); //---------------------------------------------------------------------------- #endif