kernel FunhouseMirror < namespace : "com.bobs27"; vendor : "Todd Yard"; version : 1; description : "Distorts image like a warped funhouse mirror."; > { input image4 source; output pixel4 result; parameter int warpBeginX < minValue: 0; maxValue: 1024; defaultValue: 0; description: "The start of the image warp on the x axis."; >; parameter int warpEndX < minValue: 0; maxValue: 1024; defaultValue: 512; description: "The end of the image warp on the x axis."; >; parameter float warpRatioX < minValue: 0.0; maxValue: 1.0; defaultValue: 0.5; description: "The percent of the curved warp distortion weighted towards the beginning on the x axis."; >; parameter float distortionX < minValue: 0.0; maxValue: 1.0; defaultValue: 0.5; description: "The amount of distortion to apply on the x axis."; >; parameter int warpBeginY < minValue: 0; maxValue: 1024; defaultValue: 0; description: "The start of the image warp on the y axis."; >; parameter int warpEndY < minValue: 0; maxValue: 1024; defaultValue: 512; description: "The end of the image warp on the y axis."; >; parameter float warpRatioY < minValue: 0.0; maxValue: 1.0; defaultValue: 0.5; description: "The percent of the curved warp distortion weighted towards the beginning on the y axis."; >; parameter float distortionY < minValue: 0.0; maxValue: 1.0; defaultValue: 0.5; description: "The amount of distortion to apply on the y axis."; >; void evaluatePixel() { float2 coord = outCoord(); int firstHalf; // only run this if we have distortion to apply on x axis if (distortionX > 0.0) { int x = int(coord.x); float tX; float fullWarpX = float(warpEndX - warpBeginX); // only run this if pixel is within full warp range if (x > warpBeginX && x < warpEndX) { // find difference between pixel position and beginning of effect tX = float(x - warpBeginX); firstHalf = 0; // this means we are in first half of effect if (tX/fullWarpX <= warpRatioX) { // we need to know the ration of just first half of effect fullWarpX *= warpRatioX; firstHalf = 1; } else { // we need to know the ration of second half of effect fullWarpX = fullWarpX-(fullWarpX*warpRatioX); // determine distance of pixel from end of effect tX = float(warpEndX - x); } // taken from Robert Penner's easing equations tX /= (fullWarpX/2.0); if (tX < 1.0) { tX = (fullWarpX/2.0)*tX*tX; } else { tX = -(fullWarpX/2.0)*((--tX)*(tX - 2.0) - 1.0); } // for first half of effect, add translation to beginning position of warp effect if (firstHalf == 1) { tX += float(warpBeginX); // otherwise subtract it from end of effect } else { tX = float(warpEndX) - tX; } // final pixel position is interpolated between original and transformed position based on distortion amount coord.x = mix(coord.x, tX, distortionX); } } // only run this if we have distortion to apply on y axis if (distortionY > 0.0) { int y = int(coord.y); float tY; float fullWarpY = float(warpEndY - warpBeginY); // only run this if pixel is within full warp range if (y > warpBeginY && y < warpEndY) { // find difference between pixel position and beginning of effect tY = float(y - warpBeginY); firstHalf = 0; // this means we are in first half of effect if (tY/fullWarpY <= warpRatioY) { // we need to know the ration of just first half of effect fullWarpY *= warpRatioY; firstHalf = 1; } else { // we need to know the ration of second half of effect fullWarpY = fullWarpY-(fullWarpY*warpRatioY); // determine distance of pixel from end of effect tY = float(warpEndY - y); } // taken from Robert Penner's easing equations tY /= (fullWarpY/2.0); if (tY < 1.0) { tY = (fullWarpY/2.0)*tY*tY; } else { tY = -(fullWarpY/2.0)*((--tY)*(tY - 2.0) - 1.0); } // for first half of effect, add translation to beginning position of warp effect if (firstHalf == 1) { tY += float(warpBeginY); // otherwise subtract it from end of effect } else { tY = float(warpEndY) - tY; } // final pixel position is interpolated between original and transformed position based on distortion amount coord.y = mix(coord.y, tY, distortionY); } } result = sampleNearest(source, coord); } }