From 1730be3267d05b3e758c91af8ed41a026f6babb6 Mon Sep 17 00:00:00 2001 From: jucablues Date: Thu, 16 Aug 2007 23:51:13 +0000 Subject: [PATCH] first implementation of feTurbulence renderer --- src/display/nr-filter-turbulence.cpp | 215 ++++++++++++++++++++++++--- src/display/nr-filter-turbulence.h | 43 ++++++ 2 files changed, 235 insertions(+), 23 deletions(-) diff --git a/src/display/nr-filter-turbulence.cpp b/src/display/nr-filter-turbulence.cpp index f94081612..879609009 100644 --- a/src/display/nr-filter-turbulence.cpp +++ b/src/display/nr-filter-turbulence.cpp @@ -12,6 +12,8 @@ #include "display/nr-arena-item.h" #include "display/nr-filter.h" #include "display/nr-filter-turbulence.h" +#include "display/nr-filter-utils.h" +#include namespace NR { @@ -21,7 +23,11 @@ FilterTurbulence::FilterTurbulence() numOctaves(1), seed(0), updated(false), - pix(NULL) + pix(NULL), + fTileWidth(10), //guessed + fTileHeight(10), //guessed + fTileX(1), //guessed + fTileY(1) //guessed { } @@ -58,6 +64,7 @@ void FilterTurbulence::set_updated(bool u){ } void FilterTurbulence::update_pixbuffer(FilterSlot &slot) { +//g_warning("update_pixbuf"); int bbox_x0 = (int) slot.get_arenaitem()->bbox.x0; int bbox_y0 = (int) slot.get_arenaitem()->bbox.y0; int bbox_x1 = (int) slot.get_arenaitem()->bbox.x1; @@ -72,30 +79,35 @@ void FilterTurbulence::update_pixbuffer(FilterSlot &slot) { nr_pixblock_setup_fast(pix, NR_PIXBLOCK_MODE_R8G8B8A8P, bbox_x0, bbox_y0, bbox_x1, bbox_y1, true); pix_data = NR_PIXBLOCK_PX(pix); } - -// TODO: implement here the turbulence rendering. - -/*debug: these are the available parameters - printf("XbaseFrequency = %f; ", XbaseFrequency); - printf("YbaseFrequency = %f; ", YbaseFrequency); - printf("numOctaves = %d;\n", numOctaves); - printf("seed = %f; ", seed); - printf("stitchTiles = %s; ", stitchTiles ? "stitch" : "noStitch"); - printf("type = %s;\n\n", type==0 ? "FractalNoise" : "turbulence"); -*/ - for (x=0; x < w; x++){ - for (y=0; y < h; y++){ - pix_data[4*(x + w*y)] = (unsigned char)(int(XbaseFrequency)%256); - pix_data[4*(x + w*y) + 1] = (unsigned char)(int(YbaseFrequency)%256); - pix_data[4*(x + w*y) + 2] = (unsigned char)(int(numOctaves)%256); - pix_data[4*(x + w*y) + 3] = (unsigned char)(int(seed)%256); + TurbulenceInit((long)seed); + + double point[2]; + + if (type==TURBULENCE_TURBULENCE){ + for (point[0]=0; point[0] < w; point[0]++){ + for (point[1]=0; point[1] < h; point[1]++){ + pix_data[4*(int(point[0]) + w*int(point[1]))] = CLAMP_D_TO_U8( turbulence(0,point)*255 ); + pix_data[4*(int(point[0]) + w*int(point[1])) + 1] = CLAMP_D_TO_U8( turbulence(1,point)*255 ); + pix_data[4*(int(point[0]) + w*int(point[1])) + 2] = CLAMP_D_TO_U8( turbulence(2,point)*255 ); + pix_data[4*(int(point[0]) + w*int(point[1])) + 3] = CLAMP_D_TO_U8( turbulence(3,point)*255 ); + } + } + } else { + for (point[0]=0; point[0] < w; point[0]++){ + for (point[1]=0; point[1] < h; point[1]++){ + pix_data[4*(int(point[0]) + w*int(point[1]))] = CLAMP_D_TO_U8( ((turbulence(0,point)*255) +255)/2 ); + pix_data[4*(int(point[0]) + w*int(point[1])) + 1] = CLAMP_D_TO_U8( ((turbulence(1,point)*255)+255)/2 ); + pix_data[4*(int(point[0]) + w*int(point[1])) + 2] = CLAMP_D_TO_U8( ((turbulence(2,point)*255) +255)/2 ); + pix_data[4*(int(point[0]) + w*int(point[1])) + 3] = CLAMP_D_TO_U8( ((turbulence(3,point)*255) +255)/2 ); + } } } updated=true; } int FilterTurbulence::render(FilterSlot &slot, Matrix const &trans) { +//g_warning("render"); if (!updated) update_pixbuffer(slot); NRPixBlock *in = slot.get(_input); @@ -112,18 +124,175 @@ int FilterTurbulence::render(FilterSlot &slot, Matrix const &trans) { unsigned char *out_data = NR_PIXBLOCK_PX(out); for (x=x0; x < x1; x++){ for (y=y0; y < y1; y++){ - out_data[4*((x - x0)+w*(y - y0))] = pix_data[x - bbox_x0 + w*(y - bbox_y0)]; - out_data[4*((x - x0)+w*(y - y0)) + 1] = pix_data[x - bbox_x0 + w*(y - bbox_y0)]; - out_data[4*((x - x0)+w*(y - y0)) + 2] = pix_data[x - bbox_x0 + w*(y - bbox_y0)]; - out_data[4*((x - x0)+w*(y - y0)) + 3] = pix_data[x - bbox_x0 + w*(y - bbox_y0)]; + out_data[4*((x - x0)+w*(y - y0))] = pix_data[4*(x - bbox_x0 + w*(y - bbox_y0)) ]; + out_data[4*((x - x0)+w*(y - y0)) + 1] = pix_data[4*(x - bbox_x0 + w*(y - bbox_y0))+1]; + out_data[4*((x - x0)+w*(y - y0)) + 2] = pix_data[4*(x - bbox_x0 + w*(y - bbox_y0))+2]; + out_data[4*((x - x0)+w*(y - y0)) + 3] = pix_data[4*(x - bbox_x0 + w*(y - bbox_y0))+3]; } } - out->empty = FALSE; slot.set(_output, out); return 0; } +long FilterTurbulence::Turbulence_setup_seed(long lSeed) +{ + if (lSeed <= 0) lSeed = -(lSeed % (RAND_m - 1)) + 1; + if (lSeed > RAND_m - 1) lSeed = RAND_m - 1; + return lSeed; +} + +long FilterTurbulence::TurbulenceRandom(long lSeed) +{ + long result; + result = RAND_a * (lSeed % RAND_q) - RAND_r * (lSeed / RAND_q); + if (result <= 0) result += RAND_m; + return result; +} + +void FilterTurbulence::TurbulenceInit(long lSeed) +{ +g_warning("init"); + double s; + int i, j, k; + lSeed = Turbulence_setup_seed(lSeed); + for(k = 0; k < 4; k++) + { + for(i = 0; i < BSize; i++) + { + uLatticeSelector[i] = i; + for (j = 0; j < 2; j++) + fGradient[k][i][j] = (double)(((lSeed = TurbulenceRandom(lSeed)) % (BSize + BSize)) - BSize) / BSize; + s = double(sqrt(fGradient[k][i][0] * fGradient[k][i][0] + fGradient[k][i][1] * fGradient[k][i][1])); + fGradient[k][i][0] /= s; + fGradient[k][i][1] /= s; + } + } + while(--i) + { + k = uLatticeSelector[i]; + uLatticeSelector[i] = uLatticeSelector[j = (lSeed = TurbulenceRandom(lSeed)) % BSize]; + uLatticeSelector[j] = k; + } + for(i = 0; i < BSize + 2; i++) + { + uLatticeSelector[BSize + i] = uLatticeSelector[i]; + for(k = 0; k < 4; k++) + for(j = 0; j < 2; j++) + fGradient[k][BSize + i][j] = fGradient[k][i][j]; + } +} + +double FilterTurbulence::TurbulenceNoise2(int nColorChannel, double vec[2], StitchInfo *pStitchInfo) +{ + int bx0, bx1, by0, by1, b00, b10, b01, b11; + double rx0, rx1, ry0, ry1, *q, sx, sy, a, b, t, u, v; + int i, j; + t = vec[0] + PerlinN; + bx0 = (int)t; + bx1 = bx0+1; + rx0 = t - (int)t; + rx1 = rx0 - 1.0f; + t = vec[1] + PerlinN; + by0 = (int)t; + by1 = by0+1; + ry0 = t - (int)t; + ry1 = ry0 - 1.0f; + // If stitching, adjust lattice points accordingly. + if(pStitchInfo != NULL) + { + if(bx0 >= pStitchInfo->nWrapX) + bx0 -= pStitchInfo->nWidth; + if(bx1 >= pStitchInfo->nWrapX) + bx1 -= pStitchInfo->nWidth; + if(by0 >= pStitchInfo->nWrapY) + by0 -= pStitchInfo->nHeight; + if(by1 >= pStitchInfo->nWrapY) + by1 -= pStitchInfo->nHeight; + } + bx0 &= BM; + bx1 &= BM; + by0 &= BM; + by1 &= BM; + i = uLatticeSelector[bx0]; + j = uLatticeSelector[bx1]; + b00 = uLatticeSelector[i + by0]; + b10 = uLatticeSelector[j + by0]; + b01 = uLatticeSelector[i + by1]; + b11 = uLatticeSelector[j + by1]; + sx = double(s_curve(rx0)); + sy = double(s_curve(ry0)); + q = fGradient[nColorChannel][b00]; u = rx0 * q[0] + ry0 * q[1]; + q = fGradient[nColorChannel][b10]; v = rx1 * q[0] + ry0 * q[1]; + a = turb_lerp(sx, u, v); + q = fGradient[nColorChannel][b01]; u = rx0 * q[0] + ry1 * q[1]; + q = fGradient[nColorChannel][b11]; v = rx1 * q[0] + ry1 * q[1]; + b = turb_lerp(sx, u, v); + return turb_lerp(sy, a, b); +} + +double FilterTurbulence::turbulence(int nColorChannel, double *point) +{ +//g_warning("turbulence"); + StitchInfo stitch; + StitchInfo *pStitchInfo = NULL; // Not stitching when NULL. + // Adjust the base frequencies if necessary for stitching. + if(stitchTiles) + { + // When stitching tiled turbulence, the frequencies must be adjusted + // so that the tile borders will be continuous. + if(XbaseFrequency != 0.0) + { + double fLoFreq = double(floor(fTileWidth * XbaseFrequency)) / fTileWidth; + double fHiFreq = double(ceil(fTileWidth * XbaseFrequency)) / fTileWidth; + if(XbaseFrequency / fLoFreq < fHiFreq / XbaseFrequency) + XbaseFrequency = fLoFreq; + else + XbaseFrequency = fHiFreq; + } + if(YbaseFrequency != 0.0) + { + double fLoFreq = double(floor(fTileHeight * YbaseFrequency)) / fTileHeight; + double fHiFreq = double(ceil(fTileHeight * YbaseFrequency)) / fTileHeight; + if(YbaseFrequency / fLoFreq < fHiFreq / YbaseFrequency) + YbaseFrequency = fLoFreq; + else + YbaseFrequency = fHiFreq; + } + // Set up TurbulenceInitial stitch values. + pStitchInfo = &stitch; + stitch.nWidth = int(fTileWidth * XbaseFrequency + 0.5f); + stitch.nWrapX = int(fTileX * XbaseFrequency + PerlinN + stitch.nWidth); + stitch.nHeight = int(fTileHeight * YbaseFrequency + 0.5f); + stitch.nWrapY = int(fTileY * YbaseFrequency + PerlinN + stitch.nHeight); + } + double fSum = 0.0f; + double vec[2]; + vec[0] = point[0] * XbaseFrequency; + vec[1] = point[1] * YbaseFrequency; + double ratio = 1; + for(int nOctave = 0; nOctave < numOctaves; nOctave++) + { + if(type==TURBULENCE_FRACTALNOISE) + fSum += double(TurbulenceNoise2(nColorChannel, vec, pStitchInfo) / ratio); + else + fSum += double(fabs(TurbulenceNoise2(nColorChannel, vec, pStitchInfo)) / ratio); + vec[0] *= 2; + vec[1] *= 2; + ratio *= 2; + if(pStitchInfo != NULL) + { + // Update stitch values. Subtracting PerlinN before the multiplication and + // adding it afterward simplifies to subtracting it once. + stitch.nWidth *= 2; + stitch.nWrapX = 2 * stitch.nWrapX - PerlinN; + stitch.nHeight *= 2; + stitch.nWrapY = 2 * stitch.nWrapY - PerlinN; + } + } + return fSum; +} + } /* namespace NR */ /* diff --git a/src/display/nr-filter-turbulence.h b/src/display/nr-filter-turbulence.h index 1e2171e83..db2b2854a 100644 --- a/src/display/nr-filter-turbulence.h +++ b/src/display/nr-filter-turbulence.h @@ -24,6 +24,33 @@ enum FilterTurbulenceType { TURBULENCE_ENDTYPE }; +struct StitchInfo +{ + int nWidth; // How much to subtract to wrap for stitching. + int nHeight; + int nWrapX; // Minimum value to wrap. + int nWrapY; +}; + +/* Produces results in the range [1, 2**31 - 2]. +Algorithm is: r = (a * r) mod m +where a = 16807 and m = 2**31 - 1 = 2147483647 +See [Park & Miller], CACM vol. 31 no. 10 p. 1195, Oct. 1988 +To test: the algorithm should produce the result 1043618065 +as the 10,000th generated number if the original seed is 1. +*/ +#define RAND_m 2147483647 /* 2**31 - 1 */ +#define RAND_a 16807 /* 7**5; primitive root of m */ +#define RAND_q 127773 /* m / a */ +#define RAND_r 2836 /* m % a */ +#define BSize 0x100 +#define BM 0xff +#define PerlinN 0x1000 +#define NP 12 /* 2^PerlinN */ +#define NM 0xfff +#define s_curve(t) ( t * t * (3. - 2. * t) ) +#define turb_lerp(t, a, b) ( a + t * (b - a) ) + class FilterTurbulence : public FilterPrimitive { public: FilterTurbulence(); @@ -40,6 +67,13 @@ public: virtual void set_type(FilterTurbulenceType t); virtual void set_updated(bool u); private: + + long Turbulence_setup_seed(long lSeed); + long TurbulenceRandom(long lSeed); + void TurbulenceInit(long lSeed); + double TurbulenceNoise2(int nColorChannel, double vec[2], StitchInfo *pStitchInfo); + double turbulence(int nColorChannel, double *point); + double XbaseFrequency, YbaseFrequency; int numOctaves; double seed; @@ -48,6 +82,15 @@ private: bool updated; NRPixBlock *pix; unsigned char *pix_data; + + int uLatticeSelector[BSize + BSize + 2]; + double fGradient[4][BSize + BSize + 2][2]; + + double fTileWidth; + double fTileHeight; + + double fTileX; + double fTileY; }; } /* namespace NR */ -- 2.30.2