123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480 |
- //-------------------------------------------------
- //
- // 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 <malloc.h>
- #include <memory.h>
- #include <math.h>
- #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;i<image->ySize;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;i<dst->xSize;++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;i<dst->xSize;++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;k<tmp->ySize; ++k)
- {
- getRow(raster,src, k);
- for (i=0;i<tmp->xSize;++i)
- {
- weight = 0.0;
- for (j=0;j<contrib[i].n;++j)
- {
- weight += raster[contrib[i].p[j].pixel] * contrib[i].p[j].weight;
- }
-
- putPixel(tmp,i,k,(float)CLAMP(weight,BLACK_PIXEL,WHITE_PIXEL));
- }
- }
-
- free(raster);
- raster = NULL;
-
- for (i=0;i<tmp->xSize; ++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;i<dst->ySize;++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;i<dst->ySize;++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;k<dst->xSize;++k)
- {
- getCol(raster,tmp,k);
- for (i=0;i<dst->ySize;++i)
- {
- weight = 0.0;
- for (j=0;j<contrib[i].n;++j)
- {
- weight += raster[contrib[i].p[j].pixel] * contrib[i].p[j].weight;
- }
-
- putPixel(dst,k,i,(float)CLAMP(weight,BLACK_PIXEL,WHITE_PIXEL));
- }
- }
-
- free(raster);
-
- for (i=0;i<dst->ySize; ++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
|