[opengtl-commits] [665] add droste filter effect |
[ Thread Index |
Date Index
| More lists.tuxfamily.org/opengtl-commits Archives
]
Revision: 665
Author: cyrille
Date: 2009-03-23 17:47:13 +0100 (Mon, 23 Mar 2009)
Log Message:
-----------
add droste filter effect
Added Paths:
-----------
trunk/shiva-collections/filters/Droste.shiva
Property Changed:
----------------
trunk/shiva-collections/
Property changes on: trunk/shiva-collections
___________________________________________________________________
Name: svn:ignore
-
..kdev4
shiva-collections.kdev4
+ .kdev4
shiva-collections.kdev4
build
Added: trunk/shiva-collections/filters/Droste.shiva
===================================================================
--- trunk/shiva-collections/filters/Droste.shiva (rev 0)
+++ trunk/shiva-collections/filters/Droste.shiva 2009-03-23 16:47:13 UTC (rev 665)
@@ -0,0 +1,474 @@
+<
+ parameters: <
+ Spiral: <
+ innerRadius:
+ <
+ type: float;
+ minValue:0.000001;
+ maxValue:1.0;
+ defaultValue:0.25;
+ description: "The inner radius of the repeating annular";
+ >;
+
+ outerRadius:
+ <
+ type: float;
+ minValue:0.000001;
+ maxValue:1.0;
+ defaultValue:1.0;
+ description: "The outer radius of the repeating annular";
+ >;
+
+ periodicity:
+ <
+ type: float;
+ minValue:-6.0;
+ maxValue: 6.0;
+ defaultValue:1.0;
+ description: "The number of image the image is repeated on each level";
+ >;
+
+ strands:
+ <
+ type: float;
+ minValue:-6.0;
+ maxValue: 6.0;
+ defaultValue:1.0;
+ description: "The number of strands of the spiral";
+ >;
+
+ strandMirror:
+ <
+ type: int;
+ minValue:0;
+ maxValue:1;
+ defaultValue:0;
+ description: "Activate for smoother repeating when using more than one strand";
+ >;
+ >;
+
+ Position: <
+ zoom:
+ <
+ type: float;
+ minValue:0.0;
+ maxValue:30.0;
+ defaultValue:0.0;
+ description: "Overall image magnification";
+ >;
+
+ rotate: <
+ type: float;
+ minValue: -360.0;
+ maxValue: 360.0;
+ defaultValue: 0.0;
+ description: "Overall image rotation";
+ >;
+ xcenter: <
+ label: "Input Panning x";
+ type: float;
+ minValue:-1.0;
+ defaultValue: 0.5;
+ maxValue:1.0;
+ >;
+ ycenter: <
+ label: "Input Panning y";
+ type: float;
+ minValue:-1.0;
+ defaultValue: 0.5;
+ maxValue:1.0;
+ >;
+ xcenterShift: <
+ label: "Spiral Center x";
+ type: float;
+ minValue:-1.0;
+ maxValue:1.0;
+ defaultValue:0.0;
+ >;
+ ycenterShift: <
+ label: "Spiral Center y";
+ type: float;
+ minValue:-1.0;
+ maxValue:1.0;
+ defaultValue:0.0;
+ >;
+ >;
+ levels: <
+ numberOfLevels:
+ <
+ type: int;
+ minValue:1;
+ maxValue:20;
+ defaultValue:9;
+ description: "The number of repeating levels of the spiral";
+ >;
+
+ startLevel:
+ <
+ type: int;
+ minValue:1;
+ maxValue:20;
+ defaultValue:3;
+ description: "The starting spiral level";
+ >;
+ >;
+
+ enableTransparencyInside:
+ <
+ type: int;
+ minValue:0;
+ maxValue:1;
+ defaultValue:0;
+ description: "Enable for images with transparent middle areas (such as a picture frame).";
+ >;
+
+ enableTransparencyOutside:
+ <
+ type: int;
+ minValue:0;
+ maxValue:1;
+ defaultValue:0;
+ description: "Enable for images with transparent areas around the outside.";
+ >;
+
+ untwist:
+ <
+ type: int;
+ minValue:0;
+ maxValue:1;
+ defaultValue:0;
+ description: "Unroll the circular annular of the image.";
+ >;
+
+ setAutoPeriodicity:
+ <
+ type: int;
+ minValue:0;
+ maxValue:1;
+ defaultValue:0;
+ description: "Automatically set the ideal periodicity for the current radius settings.";
+ >;
+
+ enablePoles:
+ <
+ type: int;
+ minValue:0;
+ maxValue:1;
+ defaultValue:0;
+ description: "Show both poles";
+ >;
+
+ enableHyperDroste:
+ <
+ type: int;
+ minValue:0;
+ maxValue:1;
+ defaultValue:0;
+ description: "Enable hyper droste effect. Applies when enablePoles active.";
+ >;
+
+ tilePoles:
+ <
+ type: int;
+ minValue:0;
+ maxValue:1;
+ defaultValue:0;
+ description: "Enable for hyper droste option.";
+ >;
+
+ fractalPoints: <
+ type: int;
+ minValue:1;
+ maxValue:10;
+ defaultValue:1;
+ description: "Used by hyper droste option.";
+ >;
+ >;
+>;
+
+// float3 polarCoordinates
+// <
+// minValue: float3(-180, -100, -100);
+// maxValue: float3(180, 100, 100);
+// defaultValue: float3(90, 0, 0);
+// description: "Polar rotation, latitude and longitude";
+// >;
+
+kernel Droste
+{
+ const float pi = 3.14159265358979323846;
+ const float2 I = { 0.0, 1.0};
+ const float2 imsize = { 300, 300 };
+ const float3 polarCoordinates = { 90, 0, 0 };
+ const float2 center = { xcenter, ycenter };
+ const float2 centerShift = { xcenterShift + 1.0, ycenterShift + 1.0 };
+ dependent float r1, r2, p1, p2, w, h, alphaThreshold;
+ dependent float2 _rotate, xBounds, yBounds, xyMiddle, minDimension, _zoom;
+ dependent bool showPoles, hyperDroste, tileBasedOnTransparency, transparentPointsIn, twist;
+
+ float length( float2 v)
+ {
+ v *= v;
+ return sqrt( v[0] + v[1] );
+ }
+
+ float2 complexMult(float2 a, float2 b)
+ {
+ return float2(a.x*b.x - a.y*b.y, a.x*b.y + a.y*b.x);
+ }
+ float complexMag( float2 z)
+ {
+ z *= z;
+ return z[0] + z[1];
+ }
+ float2 complexReciprocal(float2 z)
+ {
+ return float2(z.x / complexMag(z), -z.y / complexMag(z));
+ }
+ float2 complexDivision(float2 a, float2 b)
+ {
+ return complexMult(a, complexReciprocal(b));
+ }
+ float complexArg(float2 z)
+ {
+ return atan2(z.y, z.x);
+ }
+ float2 complexLog(float2 z)
+ {
+ return float2(log(length(z)), complexArg(z));
+ }
+ float2 complexExp(float2 z)
+ {
+ return float2(exp(z.x) * cos(z.y), exp(z.x) * sin(z.y));
+ }
+ float sinh(float x)
+ {
+ return (exp(x) - exp(-x)) / 2.0;
+ }
+ float cosh(float x)
+ {
+ return (exp(x) + exp(-x)) / 2.0;
+ }
+ float2 complexSin(float2 z)
+ {
+ return float2(sin(z.x) * cosh(z.y), cos(z.x) * sinh(z.y));
+ }
+ float2 complexCos(float2 z)
+ {
+ return float2(cos(z.x) * cosh(z.y), -sin(z.x) * sinh(z.y));
+ }
+ float2 complexTan(float2 z)
+ {
+ return float2(sin(2.0 * z.x)/(cos(2.0 * z.x) + cosh(2.0 * z.y)), sinh(2.0 * z.y)/(cos(2.0 * z.x) + cosh(2.0 * z.y)));
+ }
+ float2 complexSinh(float2 z)
+ {
+ return float2(sinh(z.x) * cos(z.y), cosh(z.x) * sin(z.y));
+ }
+ float2 complexCosh(float2 z)
+ {
+ return float2(cosh(z.x) * cos(z.y), sinh(z.x) * sin(z.y));
+ }
+ float2 complexTanh(float2 z)
+ {
+ return float2(sinh(2.0 * z.x)/(cosh(2.0 * z.a) + cos(2.0 * z.y)), sin(2.0 * z.y)/(cosh(2.0 * z.x) + cos(2.0 * z.y)));
+ }
+ float2 polar(float r, float a)
+ {
+ return float2(cos(a) * r, sin(a) * r);
+ }
+ float2 power(float2 z, float p)
+ {
+ return polar(pow(length(z), float(p)), float(p) * complexArg(z));
+ }
+
+ void evaluateDependents()
+ {
+ // Set code variables
+ r1 = innerRadius;
+ r2 = outerRadius;
+ p1 = periodicity;
+ if (p1 == 0.0) p1 = 0.001; // Prevent divide by zero
+ p2 = strands;
+ transparentPointsIn = ( enableTransparencyOutside == 0 );
+ tileBasedOnTransparency = (enableTransparencyInside == 1 or not transparentPointsIn);
+ twist = (untwist == 0);
+ alphaThreshold = 0.01;
+
+ w = imsize.x;
+ h = imsize.y;
+ float mdF = min(w, h) / 2.0;
+ minDimension = float2(mdF, mdF);
+
+ // Autoset periodicity
+ if (setAutoPeriodicity == 1) {
+ p1 = p2/2.0 * (1.0 + sqrt(1.0 - pow(log(r2/r1)/pi, 2.0)));
+ }
+
+ // Set rotation
+ _rotate = float2((pi/180.0) * rotate, 0.0);
+ // Set zoom
+ _zoom = float2(exp(zoom) + innerRadius - 1.0, 0.0);
+
+ // Scale viewport pixels to complex plane
+ if (twist) {
+ xBounds = float2(-r2, r2);
+ yBounds = float2(-r2, r2);
+ } else {
+ xBounds = float2(-log(r2/r1), log(r2/r1));
+ yBounds = float2(0.0, 2.1 * pi);
+ }
+
+ xyMiddle = float2(0.5 * (xBounds.x + xBounds.y), 0.5 * (yBounds.x + yBounds.y) );
+ float2 xyRange = float2(xBounds.y - xBounds.x, yBounds.y - yBounds.x);
+ xyRange.x = xyRange.y * (w / h);
+ xBounds = float2(xyMiddle.x - 0.5 * xyRange.x, xyMiddle.x + 0.5 * xyRange.x);
+
+ // Polar options
+ showPoles = (enablePoles == 1);
+ hyperDroste = (enableHyperDroste == 1);
+
+ }
+ void evaluatePixel(image img, out pixel result)
+ {
+ float2 s = result.coord;
+ float2 z; float2 ratio; float2 polar;
+ float radius; float theta; float div;
+ int iteration;
+
+ float2 sbis = s / imsize - center + 0.5;
+ z = float2(( xBounds.x + (xBounds.y - xBounds.x) * sbis.x),
+ ( yBounds.x + (yBounds.y - yBounds.x) * sbis.y));
+ // Only allow for procedural zooming/scaling in the standard coordinates
+ if (twist) {
+ z = xyMiddle + complexMult( complexDivision((z - xyMiddle), _zoom), complexExp(complexMult(-I, _rotate)));
+ }
+
+ // Extra options
+
+ polar = (float2(polarCoordinates.y, polarCoordinates.z) * w / s.x) / 100.0;
+
+ if (showPoles) {
+ theta = (pi/180.0) * polarCoordinates.x;
+
+ div = (1.0 + pow(z.x, 2.0) + pow(z.y, 2.0) + ((1.0 - pow(z.x, 2.0) - pow(z.y, 2.0)) * cos(theta)) - (2.0 * z.x * sin(theta))) / 2.0;
+ z.x = z.x * cos(theta) + ((1.0 - pow(z.x, 2.0) - pow(z.y, 2.0)) * sin(theta) / 2.0);
+ z = complexDivision(z, float2(div, 0.0));
+ } else {
+ if (hyperDroste) {
+ z = complexSin(z);
+ }
+
+ if (tilePoles == 1) {
+ z = power(z, fractalPoints);
+ z = complexTan(complexMult(z, float2(2.0, 0.0)));
+ }
+ }
+
+ z += polar;
+ if (twist) {
+ z = complexLog(complexDivision(z, float2(r1, 0.0)));
+ }
+
+ // Start Droste-effect code
+ float2 alpha = float2(atan((p2/p1) * (log(r2/r1) / (2.0*pi))), 0.0);
+ float2 f = float2(cos(alpha.x), 0.0);
+ float2 beta = complexMult(f, complexExp(complexMult(alpha, I)));
+
+ //The angle of rotation between adjacent annular levels
+ float2 angle = float2(-2.0 * pi * p1, 0.0);
+
+ if (p2 > 0.0) angle = -angle;
+ if (strandMirror == 1) angle /= strands;
+
+ z = complexDivision(complexMult(float2(p1,0), z), beta);
+ z = complexMult(float2(r1,0), complexExp(z));
+ // End Droste-effect code
+
+ if (tileBasedOnTransparency && startLevel > 0) {
+ if (!transparentPointsIn) ratio = complexMult(float2(r2/r1, 0.0), complexExp(complexMult(angle, I)));
+ if ( transparentPointsIn) ratio = complexMult(float2(r1/r2, 0.0), complexExp(complexMult(angle,-I)));
+ z = complexMult(z, power(ratio, startLevel));
+ }
+
+ // When tiling based on transparency, color is accumulated into the colorSoFar variable,
+ // while alphaRemaining tells how much remains for lower layers to contribute (initially 1,
+ // finally 0).
+ float alphaRemaining = 1.0;
+ float2 d = (z + centerShift) * minDimension ;
+ pixel src = img.sampleNearest(d);
+ float alphasrc = src[3]; // TODO get alpha from pixel
+ float4 colorSoFar = (src * (alphasrc * alphaRemaining));
+ alphaRemaining *= (1.0 - alphasrc);
+
+ // do we need to look inward from the current point, or outward?
+ int sign = 0;
+
+ if(tileBasedOnTransparency)
+ {
+ if(alphaRemaining > alphaThreshold)
+ {
+ if ( transparentPointsIn ) {
+ sign=-1;
+ } else {
+ sign= 1;
+ }
+ }
+ } else {
+ radius = length( z );
+ if (radius < r1) {
+ sign = -1;
+ } else if (radius > r2) {
+ sign= 1;
+ }
+ }
+ ratio = 1.0;
+ if (sign < 0) ratio = complexMult(float2(r2/r1, 0.0), complexExp(complexMult(angle, I)));
+ else ratio = complexMult(float2(r1/r2, 0.0), complexExp(complexMult(angle, -I)));
+
+ iteration = startLevel;
+ int maxIteration = numberOfLevels + startLevel - 1;
+
+ // Iteratively move inward or outward, until
+ // the point has radius r in [r1, r2), if tileBasedOnTransparency=false
+ // or until alphaRemaining=0, if tileBasedOnTransparency=true
+ // In the latter case, we accumulate color at each step
+
+ while (sign != 0 && iteration < maxIteration) {
+ z = complexMult(z, ratio);
+ float2 d = (z + centerShift) * minDimension ;
+ pixel src = img.sampleNearest(d);
+ float alphasrc = src[3]; // TODO get alpha from src
+ colorSoFar += (src * (alphasrc * alphaRemaining));
+ alphaRemaining *= ( 1 - alphasrc );
+ radius = length( z );
+ sign=0;
+ if(tileBasedOnTransparency )
+ {
+ if(alphaRemaining > alphaThreshold)
+ {
+ if ( transparentPointsIn ) {
+ sign=-1;
+ } else {
+ sign= 1;
+ }
+ }
+ } else {
+ radius = length( z );
+ if (radius < r1) {
+ sign = -1;
+ } else if (radius > r2) {
+ sign= 1;
+ }
+ }
+ ++iteration;
+ }
+
+ result = colorSoFar;
+ result[3] = 1.0;
+ }
+ region changed(region changed_input_region, int input_index, region input_DOD[])
+ {
+ return changed_input_region;
+ }
+}