Skip to content
Browse files

replaced ColorMap with LUT shader and added Curves shader

  • Loading branch information...
1 parent c4da6a4 commit c29b9682201f541b0df79b20c16ee311d6b8e951 @inspirit committed
View
BIN bin/gpuimage_showcase.swf
Binary file not shown.
View
43 examples/GPUImageShowcase.as
@@ -13,6 +13,7 @@ package
import flash.display3D.textures.Texture;
import flash.events.Event;
import flash.events.MouseEvent;
+ import flash.geom.Point;
import flash.media.Camera;
import flash.media.Video;
import ru.inspirit.gpu.image.effects.GPUImageAnselEffect;
@@ -24,10 +25,12 @@ package
import ru.inspirit.gpu.image.effects.GPUImageTiltShiftEffect;
import ru.inspirit.gpu.image.effects.GPUImageToonEffect;
import ru.inspirit.gpu.image.effects.GPUImageXProcessEffect;
- import ru.inspirit.gpu.image.filters.GPUImageColorMapping;
+ import ru.inspirit.gpu.image.filters.GPUImageColorMatrix;
+ import ru.inspirit.gpu.image.filters.GPUImageCurves;
import ru.inspirit.gpu.image.filters.GPUImageEmboss;
import ru.inspirit.gpu.image.filters.GPUImageGaussianBlur;
import ru.inspirit.gpu.image.filters.GPUImageGrayscale;
+ import ru.inspirit.gpu.image.filters.GPUImageLUT;
import ru.inspirit.gpu.image.filters.GPUImagePosterize;
import ru.inspirit.gpu.image.filters.GPUImageSepia;
import ru.inspirit.gpu.image.filters.GPUImageSobelEdges;
@@ -139,8 +142,41 @@ package
var lomoMapBmp:BitmapData = Bitmap(new lomo_ass).bitmapData;
lomoTexture.uploadFromBitmapData(lomoMapBmp, 0);
- var colorMap:GPUImageColorMapping = new GPUImageColorMapping();
- colorMap.colorMapTexture = lomoTexture;
+ var colorMap:GPUImageLUT = new GPUImageLUT();
+ colorMap.lutTexture = lomoTexture
+
+ // using Curves
+ var lomoGroup:GPUImageFilterGroup = new GPUImageFilterGroup();
+ var curves:GPUImageCurves = new GPUImageCurves();
+ curves.addCurvePoint(GPUImageCurves.CURVE_CHANNEL_RED,
+ new Point(0, 0),
+ new Point(60, 30),
+ new Point(190, 220),
+ new Point(255, 255)
+ );
+ curves.addCurvePoint(GPUImageCurves.CURVE_CHANNEL_GREEN,
+ new Point(0, 0),
+ new Point(60, 30),
+ new Point(190, 220),
+ new Point(255, 255)
+ );
+ curves.addCurvePoint(GPUImageCurves.CURVE_CHANNEL_BLUE,
+ new Point(0, 0),
+ new Point(30, 60),
+ new Point(220, 190),
+ new Point(255, 255)
+ );
+ // update texture
+ curves.update();
+
+ var clrMat:GPUImageColorMatrix = new GPUImageColorMatrix();
+ clrMat.saturation = 1.5;
+ var lomoVig:GPUImageVignette = new GPUImageVignette();
+
+ lomoGroup.addProcessor(curves);
+ lomoGroup.addProcessor(clrMat);
+ lomoGroup.addProcessor(lomoVig);
+ //
var xpro:GPUImageXProcessEffect = new GPUImageXProcessEffect(0.5);
@@ -176,6 +212,7 @@ package
_imageProcessors.push(new GPUImageGeorgiaEffect);
_imageProcessors.push(xpro);
_imageProcessors.push(colorMap);
+ _imageProcessors.push(lomoGroup);
_imageProcessors.push(_gpuGray);
_imageProcessors.push(_gpuSepia);
_imageProcessors.push(_gpuGauss);
View
138 src/ru/inspirit/gpu/image/effects/GPUImageXProcessEffect.as
@@ -8,6 +8,7 @@ package ru.inspirit.gpu.image.effects
import flash.display3D.textures.Texture;
import flash.geom.Matrix;
import flash.geom.Point;
+ import ru.inspirit.gpu.image.filters.GPUImageCurves;
import ru.inspirit.gpu.image.GPUImageFilter;
import ru.inspirit.gpu.image.IGPUImageProcessor;
@@ -15,7 +16,7 @@ package ru.inspirit.gpu.image.effects
* ...
* @author Eugene Zatepyakin
*/
- public final class GPUImageXProcessEffect extends GPUImageFilter
+ public final class GPUImageXProcessEffect extends GPUImageCurves
{
internal static const FRAGMENT_CODE:String =
"tex ft0, v0, fs0 <2d,linear,mipnone,clamp> \n" +
@@ -68,8 +69,6 @@ package ru.inspirit.gpu.image.effects
protected var _contrast:Number;
protected var _tint:Number;
protected var _color:uint;
- protected var _lutBmp:BitmapData;
- protected var _lutTexture:Texture;
protected var _params:Vector.<Number>;
@@ -91,58 +90,31 @@ package ru.inspirit.gpu.image.effects
1.-r, 1.-g, 1.-b, 0
]);
- createLUTTexture();
+ // setup Curves
+ addCurvePoint(GPUImageCurves.CURVE_CHANNEL_RED,
+ new Point(0, 0),
+ new Point(88, 47),
+ new Point(170, 188),
+ new Point(221, 249),
+ new Point(255, 255));
+ addCurvePoint(GPUImageCurves.CURVE_CHANNEL_GREEN,
+ new Point(0, 0),
+ new Point(65, 57),
+ new Point(184, 208),
+ new Point(255, 255));
+ addCurvePoint(GPUImageCurves.CURVE_CHANNEL_BLUE,
+ new Point(0, 29),
+ new Point(255, 226));
- _fragmentShader = agalCompiler.assemble(FRAGMENT_TYPE, FRAGMENT_CODE, AGAL_DEBUG);
- }
-
- override public function setup(context:Context3D, textureWidth:int, textureHeight:int):void
- {
- super.setup(context, textureWidth, textureHeight);
-
- if (_lutTexture)
- {
- _lutTexture.dispose();
- _lutTexture = null;
- }
+ update();
- _lutTexture = _context.createTexture(256, 256, Context3DTextureFormat.BGRA, false);
- _lutTexture.uploadFromBitmapData(_lutBmp);
+ _fragmentShader = agalCompiler.assemble(FRAGMENT_TYPE, GPUImageXProcessEffect.FRAGMENT_CODE, AGAL_DEBUG);
}
override public function activate():void
{
- _context.setProgram(_program);
+ super.activate();
_context.setProgramConstantsFromVector(FRAGMENT_TYPE, 0, _params, 3);
- _context.setTextureAt(1, _lutTexture);
- }
- override public function deactivate():void
- {
- _context.setTextureAt(1, null);
- }
-
- protected function createLUTTexture():void
- {
- // fix palettes
- var lut_r:Array = [];
- var lut_g:Array = [];
- for (var i:int = 0; i < 256; ++i)
- {
- lut_r[i] = _xproRedCurveLut[i] << 16;
- lut_g[i] = _xproGreenCurveLut[i] << 8;
- }
-
- _lutBmp = new BitmapData(256, 256, false, 0x0);
- var sh:Shape = new Shape();
- var gfx:Graphics = sh.graphics;
- var mat:Matrix = new Matrix();
- mat.createGradientBox(256,256,0);
- gfx.beginGradientFill('linear', [0x000000, 0xFFFFFF], [1, 1], [0, 255], mat);
- gfx.drawRect(0, 0, 256, 256);
- gfx.endFill();
-
- _lutBmp.draw(sh);
- _lutBmp.paletteMap(_lutBmp, _lutBmp.rect, new Point, lut_r, lut_g, _xproBlueCurveLut);
}
override public function clone():IGPUImageProcessor
@@ -151,80 +123,10 @@ package ru.inspirit.gpu.image.effects
return copy;
}
- override public function dispose():void
- {
- super.dispose();
- if (_lutBmp)
- {
- _lutBmp.dispose();
- _lutBmp = null;
- }
- if (_lutTexture)
- {
- _lutTexture.dispose();
- _lutTexture = null;
- }
- }
-
override public function toString():String
{
return 'Cross Processing';
}
-
- // taken from LightBox sources ;-)
- protected var _xproRedCurveLut:Array = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,
- 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7,
- 8, 8, 8, 9, 9, 9, 10, 10, 11, 11, 11, 12, 12, 13, 13, 14, 14, 14, 15,
- 15, 16, 16, 17, 18, 18, 19, 19, 20, 20, 21, 22, 22, 23, 24, 24, 25, 26,
- 27, 27, 28, 29, 30, 30, 31, 32, 33, 34, 35, 36, 37, 37, 38, 39, 40, 41,
- 42, 44, 44, 45, 46, 47, 49, 50, 52, 53, 54, 56, 57, 58, 60, 61, 63, 64,
- 66, 68, 69, 71, 73, 75, 76, 78, 80, 81, 83, 85, 87, 89, 91, 93, 95, 97,
- 98, 101, 103, 105, 107, 109, 111, 113, 115, 117, 119, 121, 123, 125,
- 127, 129, 131, 133, 135, 137, 139, 141, 143, 145, 147, 149, 151, 154,
- 156, 157, 159, 161, 163, 165, 167, 169, 171, 173, 175, 177, 178, 180,
- 182, 184, 185, 187, 188, 191, 192, 193, 195, 197, 198, 200, 202, 203,
- 205, 206, 208, 209, 211, 212, 214, 215, 217, 219, 220, 221, 223, 224,
- 225, 227, 228, 230, 231, 232, 234, 235, 236, 237, 239, 240, 241, 242,
- 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255 ];
- protected var _xproGreenCurveLut:Array = [ 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
- 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
- 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45,
- 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 58, 59, 60, 61, 62, 63, 64, 65,
- 67, 69, 70, 71, 72, 73, 75, 76, 77, 78, 80, 81, 82, 83, 85, 86, 87, 88,
- 90, 91, 92, 94, 95, 96, 97, 99, 100, 101, 103, 104, 105, 107, 108, 109,
- 111, 112, 113, 115, 116, 117, 119, 120, 121, 123, 124, 125, 127, 129,
- 130, 132, 133, 134, 136, 137, 138, 140, 141, 142, 144, 145, 146, 147,
- 149, 149, 150, 152, 153, 154, 155, 157, 158, 159, 160, 162, 163, 164,
- 166, 167, 168, 170, 171, 172, 173, 174, 176, 177, 178, 179, 181, 182,
- 183, 184, 185, 187, 188, 189, 190, 191, 192, 193, 195, 196, 197, 198,
- 199, 200, 201, 202, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213,
- 213, 215, 216, 217, 217, 218, 219, 220, 221, 222, 222, 223, 224, 225,
- 226, 226, 227, 228, 229, 229, 230, 231, 231, 232, 233, 233, 234, 235,
- 235, 236, 236, 237, 238, 238, 239, 239, 240, 240, 241, 241, 242, 242,
- 243, 243, 244, 244, 245, 245, 245, 246, 246, 247, 247, 248, 248, 248,
- 249, 249, 250, 250, 250, 251, 251, 251, 252, 252, 253, 253, 254, 254,
- 255, 255, 255 ];
- protected var _xproBlueCurveLut:Array = [ 21, 21, 21, 22, 23, 24, 25, 26,
- 27, 28, 29, 29, 30, 31, 32, 33, 34, 34, 35, 36, 37, 38, 39, 39, 40, 41,
- 42, 43, 44, 44, 45, 46, 47, 48, 49, 49, 50, 51, 52, 53, 54, 54, 55, 56,
- 57, 58, 59, 59, 60, 61, 62, 63, 64, 64, 65, 66, 67, 68, 69, 69, 70, 71,
- 72, 73, 74, 74, 75, 76, 77, 78, 79, 80, 80, 81, 82, 83, 84, 84, 85, 86,
- 87, 88, 89, 89, 91, 91, 92, 93, 94, 95, 95, 96, 97, 98, 99, 100, 101,
- 101, 102, 103, 104, 105, 106, 106, 107, 108, 109, 110, 111, 111, 112,
- 113, 114, 115, 115, 116, 117, 118, 119, 120, 121, 121, 122, 123, 124,
- 125, 126, 126, 127, 128, 129, 130, 131, 132, 132, 133, 134, 135, 136,
- 137, 137, 138, 139, 140, 141, 142, 142, 143, 144, 145, 146, 147, 147,
- 148, 149, 150, 151, 152, 152, 153, 154, 155, 156, 157, 157, 158, 159,
- 160, 160, 162, 162, 163, 164, 165, 166, 167, 167, 168, 169, 170, 171,
- 172, 172, 173, 174, 175, 176, 176, 177, 178, 179, 180, 181, 181, 182,
- 183, 184, 185, 186, 186, 187, 188, 189, 190, 191, 191, 192, 193, 194,
- 195, 196, 197, 198, 198, 199, 200, 201, 202, 203, 203, 204, 205, 206,
- 207, 208, 208, 209, 210, 211, 212, 213, 213, 214, 215, 216, 217, 218,
- 218, 219, 220, 221, 222, 223, 223, 224, 225, 226, 227, 228, 228, 229,
- 230, 231, 232, 232, 233 ];
public function get contrast():Number { return _contrast; }
public function set contrast(value:Number):void
View
63 src/ru/inspirit/gpu/image/filters/GPUImageColorMapping.as
@@ -1,63 +0,0 @@
-package ru.inspirit.gpu.image.filters
-{
- import flash.display3D.textures.Texture;
- import ru.inspirit.gpu.image.GPUImageFilter;
- import ru.inspirit.gpu.image.IGPUImageProcessor;
-
- /**
- * ...
- * @author Eugene Zatepyakin
- */
- public final class GPUImageColorMapping extends GPUImageFilter
- {
- internal static const FRAGMENT_CODE:String =
- "tex ft0, v0, fs0 <2d,linear,mipnone,clamp> \n" +
- "tex ft1, ft0.xx, fs1 <2d,linear,mipnone,clamp> \n" +
- "mov ft0.x, ft1.x \n" +
- "tex ft1, ft0.yy, fs1 <2d,linear,mipnone,clamp> \n" +
- "mov ft0.y, ft1.y \n" +
- "tex ft1, ft0.zz, fs1 <2d,linear,mipnone,clamp> \n" +
- "mov ft0.z, ft1.z \n" +
- //out
- "mov oc, ft0";
-
- protected var _colorMapTexture:Texture;
-
- public function GPUImageColorMapping()
- {
- super();
-
- _fragmentShader = agalCompiler.assemble(FRAGMENT_TYPE, FRAGMENT_CODE, AGAL_DEBUG);
- }
-
- override public function activate():void
- {
- _context.setProgram(_program);
- _context.setTextureAt(1, _colorMapTexture);
- }
-
- override public function deactivate():void
- {
- _context.setTextureAt(1, null);
- }
-
- override public function clone():IGPUImageProcessor
- {
- var copy:GPUImageColorMapping = new GPUImageColorMapping();
- return copy;
- }
-
- override public function toString():String
- {
- return 'ColorMap Filter';
- }
-
- public function get colorMapTexture():Texture { return _colorMapTexture; }
- public function set colorMapTexture(value:Texture):void
- {
- _colorMapTexture = value;
- }
-
- }
-
-}
View
417 src/ru/inspirit/gpu/image/filters/GPUImageCurves.as
@@ -0,0 +1,417 @@
+package ru.inspirit.gpu.image.filters
+{
+ import flash.display.BitmapData;
+ import flash.geom.Point;
+ import flash.geom.Rectangle;
+
+ public class GPUImageCurves extends GPUImageLUT
+ {
+ public static const CURVE_INTERPOLATION_LINEAR:uint = 0;
+ public static const CURVE_INTERPOLATION_SMOOTH:uint = 1;
+
+ public static const CURVE_CHANNEL_RED:int = 2; // 1 << 1
+ public static const CURVE_CHANNEL_GREEN:int = 4; // 1 << 2
+ public static const CURVE_CHANNEL_BLUE:int = 8; // 1 << 3
+ public static const CURVE_CHANNEL_RGB:int = 14; // 2 | 4 | 8
+
+ // using array cause of sort routine :)
+ // dont wnat to use custom sort function
+ protected var _redPoints:Array;
+ protected var _greenPoints:Array;
+ protected var _bluePoints:Array;
+
+ protected var _interpolation:uint;
+
+ public function GPUImageCurves(interpolation:uint = CURVE_INTERPOLATION_SMOOTH)
+ {
+ super();
+
+ _redPoints = new Array;
+ _greenPoints = new Array;
+ _bluePoints = new Array;
+
+ _interpolation = interpolation;
+
+ clearCurve(CURVE_CHANNEL_RGB);
+ }
+
+ public function update():void
+ {
+ var redPalette:Array = calculateCurveLUT(_redPoints, 16);
+ var greenPalette:Array = calculateCurveLUT(_greenPoints, 8);
+ var bluePalette:Array = calculateCurveLUT(_bluePoints, 0);
+
+ setupLUTTexture(redPalette, greenPalette, bluePalette);
+ }
+
+ public function renderCurves():BitmapData
+ {
+ var gridColor:uint = 0xCCCCCC;
+ var render:BitmapData = new BitmapData(256, 256, false, 0xDDDDDD);
+ var i:int = 0;
+ while (i < 0x0100) {
+ render.setPixel(i, 0, gridColor);
+ render.setPixel(i, 64, gridColor);
+ render.setPixel(i, 128, gridColor);
+ render.setPixel(i, 192, gridColor);
+ render.setPixel(i, 0xFF, gridColor);
+ i++;
+ }
+ i = 0;
+ while (i < 0x0100) {
+ render.setPixel(0, i, gridColor);
+ render.setPixel(64, i, gridColor);
+ render.setPixel(128, i, gridColor);
+ render.setPixel(192, i, gridColor);
+ render.setPixel(0xFF, i, gridColor);
+ i++;
+ }
+
+ renderCurve(calculateCurveLUT(_redPoints), _redPoints, render, 0xFF0000, 0xFF0000);
+ renderCurve(calculateCurveLUT(_greenPoints), _greenPoints, render, 0x00FF00, 0x00FF00);
+ renderCurve(calculateCurveLUT(_bluePoints), _bluePoints, render, 0x0000FF, 0x0000FF);
+
+ return render;
+ }
+
+ public function addCurvePoint(channel:int, ...points):void
+ {
+ var n:int = points.length;
+ var i:int;
+ if (channel == CURVE_CHANNEL_RGB)
+ {
+ for(i = 0; i < n; ++i)
+ {
+ _redPoints.push(points[i]);
+ _greenPoints.push(points[i]);
+ _bluePoints.push(points[i]);
+ }
+ }
+ else if (channel & CURVE_CHANNEL_RED)
+ {
+ for(i = 0; i < n; ++i)
+ {
+ _redPoints.push(points[i]);
+ }
+ }
+ else if (channel & CURVE_CHANNEL_GREEN)
+ {
+ for(i = 0; i < n; ++i)
+ {
+ _greenPoints.push(points[i]);
+ }
+ }
+ else if (channel & CURVE_CHANNEL_BLUE)
+ {
+ for(i = 0; i < n; ++i)
+ {
+ _bluePoints.push(points[i]);
+ }
+ }
+ }
+
+ public function removeCurvePoint(channel:int, point:Point):void
+ {
+ var n:int;
+ var i:int;
+
+ if (channel == CURVE_CHANNEL_RGB)
+ {
+ n = _redPoints.length;
+ for(i = 0; i < n; ++i)
+ {
+ if(point.equals(_redPoints[i]))
+ {
+ _redPoints.splice(i, 1);
+ break;
+ }
+ }
+ //
+ n = _greenPoints.length;
+ for(i = 0; i < n; ++i)
+ {
+ if(point.equals(_greenPoints[i]))
+ {
+ _greenPoints.splice(i, 1);
+ break;
+ }
+ }
+ //
+ n = _bluePoints.length;
+ for(i = 0; i < n; ++i)
+ {
+ if(point.equals(_bluePoints[i]))
+ {
+ _bluePoints.splice(i, 1);
+ break;
+ }
+ }
+ }
+ else if (channel & CURVE_CHANNEL_RED)
+ {
+ n = _redPoints.length;
+ for(i = 0; i < n; ++i)
+ {
+ if(point.equals(_redPoints[i]))
+ {
+ _redPoints.splice(i, 1);
+ break;
+ }
+ }
+ }
+ else if (channel & CURVE_CHANNEL_GREEN)
+ {
+ n = _greenPoints.length;
+ for(i = 0; i < n; ++i)
+ {
+ if(point.equals(_greenPoints[i]))
+ {
+ _greenPoints.splice(i, 1);
+ break;
+ }
+ }
+ }
+ else if (channel & CURVE_CHANNEL_BLUE)
+ {
+ n = _bluePoints.length;
+ for(i = 0; i < n; ++i)
+ {
+ if(point.equals(_bluePoints[i]))
+ {
+ _bluePoints.splice(i, 1);
+ break;
+ }
+ }
+ }
+ }
+
+ public function clearCurve(channel:int):void
+ {
+ if (channel == CURVE_CHANNEL_RGB)
+ {
+ _redPoints.length = 0;
+ _greenPoints.length = 0;
+ _bluePoints.length = 0;
+ }
+ else if (channel & CURVE_CHANNEL_RED)
+ {
+ _redPoints.length = 0;
+ }
+ else if (channel & CURVE_CHANNEL_GREEN)
+ {
+ _greenPoints.length = 0;
+ }
+ else if (channel & CURVE_CHANNEL_BLUE)
+ {
+ _bluePoints.length = 0;
+ }
+ }
+
+ public function get interpolation():uint { return _interpolation; }
+ public function set interpolation(value:uint):void
+ {
+ _interpolation = value;
+ }
+
+ // original implementation by Joa Ebert
+ // from popforge image processing lib
+ // but looks like i overwrote it mostly
+ protected function calculateCurveLUT(points:Array, shift:int = 0):Array
+ {
+ var table:Array;
+ var pnts:Array;
+ var p0:Point;
+ var p1:Point;
+ var i:int;
+ var t0:Number;
+ var t1:Number;
+ var x:int;
+ var y:int;
+ var n:int;
+
+ table = new Array(0x0100);
+
+ if (points.length == 0){
+ i = 0;
+ while (i < 0x0100)
+ {
+ table[i] = 0;
+ ++i;
+ }
+ return table;
+ }
+
+ pnts = points.slice();
+ pnts.sortOn("x", Array.NUMERIC);
+ n = pnts.length;
+ if(pnts[n-1].x < 0xFF)
+ {
+ pnts.push(new Point(0xFF, pnts[n-1].y));
+ }
+ if(pnts[0].x > 0)
+ {
+ pnts.unshift(new Point(0, pnts[0].y));
+ }
+ n = pnts.length;
+
+ switch(_interpolation)
+ {
+ default:
+ case CURVE_INTERPOLATION_SMOOTH:
+ if (n > 2)
+ {
+ var spl:Spline = new Spline(pnts);
+ i = 0;
+ while (i < 256)
+ {
+ y = spl.interpolate(i) + 0.5;
+ table[i] = y < 0 ? 0 : (y > 0xFF ? 0xFF : y);
+ ++i;
+ }
+ break;
+ }
+ // otherwise just fall to linear
+ case CURVE_INTERPOLATION_LINEAR:
+ --n;
+ i = 0;
+ while (i < n) {
+ p0 = pnts[i];
+ p1 = pnts[(i + 1)|0];
+ t0 = 0;
+ t1 = Math.abs((p1.x - p0.x));
+ if (t1 != 0){
+ x = p0.x;
+ while (x <= p1.x)
+ {
+ y = p0.y + ((p1.y - p0.y) * (t0 / t1)) + 0.5;
+ table[x] = y < 0 ? 0 : (y > 0xFF ? 0xFF : y);
+ ++t0;
+ ++x;
+ }
+ }
+ ++i;
+ }
+ break;
+ }
+
+ i = 0x0100;
+ while(--i > -1)
+ {
+ table[i] <<= shift;
+ }
+
+ return table;
+ }
+
+ protected function renderCurve(table:Array, points:Array, render:BitmapData, pointColor:int=0xFF00FF, lineColor:int=0x666666):void
+ {
+ var y0:int;
+ var x:int;
+ var i:int, n:int;
+ var y:int;
+ var ty:int;
+ var p:Point;
+
+ y0 = (0xFF - table[0]);
+ x = 0;
+ while (x < 0x0100) {
+ y = (0xFF - table[x]);
+ ty = y;
+ render.setPixel(x, y, lineColor);
+ if (ty > y0){
+ while (--ty > y0) {
+ render.setPixel(x, ty, lineColor);
+ }
+ } else {
+ if (ty < y0){
+ while (++ty < y0) {
+ render.setPixel(x, ty, lineColor);
+ }
+ }
+ }
+ y0 = y;
+ x++;
+ }
+
+ i = 0;
+ n = points.length;
+ var r:Rectangle = new Rectangle(0, 0, 5, 5);
+ while (i < n) {
+ p = points[i];
+ r.x = p.x - 2;
+ r.y = 0xFF - p.y - 2;
+ render.fillRect(r, pointColor);
+ i++;
+ }
+ }
+ }
+}
+
+// Martin Heidegger found on wonderfl and gave it to me ;)
+internal final class Spline
+{
+ protected var num:int;
+
+ protected var x:Vector.<Number>;
+ protected var y:Vector.<Number>;
+ protected var z:Vector.<Number>;
+
+ public function Spline(points:Array):void
+ {
+ num = points.length;
+ x = new Vector.<Number>(num, true);
+ y = new Vector.<Number>(num, true);
+ for (var i:int = 0; i < num; ++i)
+ {
+ x[i] = points[i].x;
+ y[i] = points[i].y;
+ }
+ init();
+ }
+
+ protected function init():void
+ {
+ z = new Vector.<Number>(num);
+ var h:Vector.<Number> = new Vector.<Number>(num);
+ var d:Vector.<Number> = new Vector.<Number>(num);
+ z[0]=z[num-1]=0;
+ for (var i:int = 0; i < num - 1;++i)
+ {
+ h[i] = x[i+1]-x[i];
+ d[i+1] = (y[i+1]-y[i])/ h[i];
+ }
+ z[1]=d[2]-d[1]-h[0]*z[0];
+ d[1]=2*(x[2]-x[0]);
+ for (i = 1; i < num - 2; ++i)
+ {
+ var t:Number = h[i]/d[i];
+ z[i+1]=d[i+2]-d[i+1]-z[i]*t;
+ d[i+1]=2*(x[i+2]-x[i])-h[i]*t;
+ }
+ z[num-2] -= h[num-2]*z[num-1];
+ for (i = num - 2; i > 0; i--)
+ {
+ z[i]=(z[i]-h[i]*z[i+1])/d[i];
+ }
+ }
+
+ public function interpolate(t:Number):Number
+ {
+ var i:int=0;
+ var j:int=num-1;
+ while(i<j){
+ var k:int = (i+j) * 0.5;
+ if(x[k]<t){
+ i=k+1;
+ }else{
+ j = k;
+ }
+ }
+ if(i>0)i--;
+ var h:Number=x[i+1]-x[i];
+ var d:Number= t - x[i];
+ return (((z[i+1]-z[i])*d/h+z[i]*3)*d
+ +((y[i+1]-y[i])/ h
+ -(z[i]*2+z[i+1])*h))*d+y[i];
+ }
+}
View
124 src/ru/inspirit/gpu/image/filters/GPUImageLUT.as
@@ -0,0 +1,124 @@
+package ru.inspirit.gpu.image.filters
+{
+ import flash.display.BitmapData;
+ import flash.display.Graphics;
+ import flash.display.Shape;
+ import flash.display3D.Context3D;
+ import flash.display3D.Context3DTextureFormat;
+ import flash.display3D.textures.Texture;
+ import flash.geom.Matrix;
+ import flash.geom.Point;
+
+ import ru.inspirit.gpu.image.GPUImageFilter;
+ import ru.inspirit.gpu.image.IGPUImageProcessor;
+
+ public class GPUImageLUT extends GPUImageFilter
+ {
+ internal static const FRAGMENT_CODE:String =
+ "tex ft0, v0, fs0 <2d,linear,mipnone,clamp> \n" +
+ "tex ft1, ft0.xx, fs1 <2d,linear,mipnone,clamp> \n" +
+ "mov ft0.x, ft1.x \n" +
+ "tex ft1, ft0.yy, fs1 <2d,linear,mipnone,clamp> \n" +
+ "mov ft0.y, ft1.y \n" +
+ "tex ft1, ft0.zz, fs1 <2d,linear,mipnone,clamp> \n" +
+ "mov ft0.z, ft1.z \n" +
+ //out
+ "mov oc, ft0";
+
+ protected var _lutBitmap:BitmapData = null;
+ protected var _lutMapTexture:Texture = null;
+
+ public function GPUImageLUT()
+ {
+ super();
+
+ _fragmentShader = agalCompiler.assemble(FRAGMENT_TYPE, FRAGMENT_CODE, AGAL_DEBUG);
+ }
+
+ override public function setup(context:Context3D, textureWidth:int, textureHeight:int):void
+ {
+ super.setup(context, textureWidth, textureHeight);
+
+ if(null != _lutBitmap)
+ {
+ if(null != _lutMapTexture)
+ {
+ _lutMapTexture.dispose();
+ }
+
+ _lutMapTexture = _context.createTexture(256, 256, Context3DTextureFormat.BGRA, false);
+ _lutMapTexture.uploadFromBitmapData(_lutBitmap, 0);
+ }
+ }
+
+ override public function activate():void
+ {
+ _context.setProgram(_program);
+ _context.setTextureAt(1, _lutMapTexture);
+ }
+
+ override public function deactivate():void
+ {
+ _context.setTextureAt(1, null);
+ }
+
+ override public function clone():IGPUImageProcessor
+ {
+ var copy:GPUImageLUT = new GPUImageLUT();
+ if(_lutMapTexture) copy.lutTexture = _lutMapTexture;
+ if(_lutBitmap) copy.lutBitmap = _lutBitmap;
+ return copy;
+ }
+
+ override public function dispose():void
+ {
+ super.dispose();
+ if(_lutBitmap) _lutBitmap.dispose();
+ if(_lutMapTexture) _lutMapTexture.dispose();
+ }
+
+ override public function toString():String
+ {
+ return 'LUT Filter';
+ }
+
+ public function get lutTexture():Texture { return _lutMapTexture; }
+ public function set lutTexture(value:Texture):void
+ {
+ _lutMapTexture = value;
+ }
+
+ public function get lutBitmap():BitmapData {return _lutBitmap;}
+ public function set lutBitmap(value:BitmapData):void
+ {
+ if(value.width != 256 || value.height != 256 )
+ {
+ throw new Error("LUT Filter BitmapData needs to be 256x256 size");
+ }
+ _lutBitmap = value;
+ }
+
+ public function setupLUTTexture(redPalette:Array, greenPalette:Array, bluePalette:Array, alphaPalette:Array = null):void
+ {
+ if(!_lutBitmap) _lutBitmap = new BitmapData(256, 256, false, 0x0);
+
+ _lutBitmap.draw(_sh);
+ _lutBitmap.paletteMap(_lutBitmap, _lutBitmap.rect, new Point, redPalette, greenPalette, bluePalette, alphaPalette);
+
+ if(_lutMapTexture)
+ {
+ _lutMapTexture.uploadFromBitmapData(_lutBitmap, 0);
+ }
+ }
+
+ protected static var _sh:Shape = new Shape();
+ protected static var _gfx:Graphics = _sh.graphics;
+ protected static var _mat:Matrix = new Matrix();
+ {
+ _mat.createGradientBox(256,256,0);
+ _gfx.beginGradientFill('linear', [0x000000, 0xFFFFFF], [1, 1], [0, 255], _mat);
+ _gfx.drawRect(0, 0, 256, 256);
+ _gfx.endFill();
+ }
+ }
+}

0 comments on commit c29b968

Please sign in to comment.
Something went wrong with that request. Please try again.