| 1 | unit BGRABlurGL;
|
|---|
| 2 |
|
|---|
| 3 | {$mode objfpc}{$H+}
|
|---|
| 4 |
|
|---|
| 5 | interface
|
|---|
| 6 |
|
|---|
| 7 | uses
|
|---|
| 8 | Classes, BGRAOpenGL3D, BGRABitmapTypes, BGRACanvasGL, BGRAOpenGLType;
|
|---|
| 9 |
|
|---|
| 10 | type
|
|---|
| 11 |
|
|---|
| 12 | { TBGLBlurShader }
|
|---|
| 13 |
|
|---|
| 14 | TBGLBlurShader = class(TBGLShader3D)
|
|---|
| 15 | private
|
|---|
| 16 | function GetDirection: TPointF;
|
|---|
| 17 | function GetImageIndex: integer;
|
|---|
| 18 | function GetRadius: Single;
|
|---|
| 19 | function GetTextureSize: TPoint;
|
|---|
| 20 | procedure SetDirection(AValue: TPointF);
|
|---|
| 21 | procedure SetImageIndex(AValue: integer);
|
|---|
| 22 | procedure SetRadius(AValue: Single);
|
|---|
| 23 | procedure SetTextureSize(AValue: TPoint);
|
|---|
| 24 | protected
|
|---|
| 25 | FTextureSize: TUniformVariablePoint;
|
|---|
| 26 | FImageIndex: TUniformVariableInteger;
|
|---|
| 27 | FDirection: TUniformVariablePointF;
|
|---|
| 28 | FRadius: TUniformVariableSingle;
|
|---|
| 29 | FBlurType: TRadialBlurType;
|
|---|
| 30 | procedure StartUse; override;
|
|---|
| 31 | public
|
|---|
| 32 | constructor Create(ACanvas: TBGLCustomCanvas; ABlurType: TRadialBlurType);
|
|---|
| 33 | function FilterBlurMotion(ATexture: IBGLTexture): IBGLTexture; overload;
|
|---|
| 34 | function FilterBlurMotion(ATexture: IBGLTexture; ADirection: TPointF): IBGLTexture; overload;
|
|---|
| 35 | function FilterBlurRadial(ATexture: IBGLTexture): IBGLTexture;
|
|---|
| 36 | property ImageIndex: integer read GetImageIndex write SetImageIndex;
|
|---|
| 37 | property TextureSize: TPoint read GetTextureSize write SetTextureSize;
|
|---|
| 38 | property Direction: TPointF read GetDirection write SetDirection;
|
|---|
| 39 | property Radius: Single read GetRadius write SetRadius;
|
|---|
| 40 | property BlurType: TRadialBlurType read FBlurType;
|
|---|
| 41 | end;
|
|---|
| 42 |
|
|---|
| 43 | implementation
|
|---|
| 44 |
|
|---|
| 45 | { TBGLBlurShader }
|
|---|
| 46 |
|
|---|
| 47 | function TBGLBlurShader.GetDirection: TPointF;
|
|---|
| 48 | begin
|
|---|
| 49 | result := FDirection.Value;
|
|---|
| 50 | end;
|
|---|
| 51 |
|
|---|
| 52 | function TBGLBlurShader.GetImageIndex: integer;
|
|---|
| 53 | begin
|
|---|
| 54 | result := FImageIndex.Value;
|
|---|
| 55 | end;
|
|---|
| 56 |
|
|---|
| 57 | function TBGLBlurShader.GetRadius: Single;
|
|---|
| 58 | begin
|
|---|
| 59 | result := FRadius.Value;
|
|---|
| 60 | if FBlurType = rbPrecise then result *= 10;
|
|---|
| 61 | end;
|
|---|
| 62 |
|
|---|
| 63 | function TBGLBlurShader.GetTextureSize: TPoint;
|
|---|
| 64 | begin
|
|---|
| 65 | result := FTextureSize.Value;
|
|---|
| 66 | end;
|
|---|
| 67 |
|
|---|
| 68 | procedure TBGLBlurShader.SetDirection(AValue: TPointF);
|
|---|
| 69 | begin
|
|---|
| 70 | FDirection.Value := AValue;
|
|---|
| 71 | end;
|
|---|
| 72 |
|
|---|
| 73 | procedure TBGLBlurShader.SetImageIndex(AValue: integer);
|
|---|
| 74 | begin
|
|---|
| 75 | FImageIndex.Value := AValue;
|
|---|
| 76 | end;
|
|---|
| 77 |
|
|---|
| 78 | procedure TBGLBlurShader.SetRadius(AValue: Single);
|
|---|
| 79 | begin
|
|---|
| 80 | if FBlurType = rbPrecise then AValue /= 10;
|
|---|
| 81 | FRadius.Value := AValue;
|
|---|
| 82 | end;
|
|---|
| 83 |
|
|---|
| 84 | procedure TBGLBlurShader.SetTextureSize(AValue: TPoint);
|
|---|
| 85 | begin
|
|---|
| 86 | FTextureSize.Value:= AValue;
|
|---|
| 87 | end;
|
|---|
| 88 |
|
|---|
| 89 | constructor TBGLBlurShader.Create(ACanvas: TBGLCustomCanvas; ABlurType: TRadialBlurType);
|
|---|
| 90 | var weightFunc: string;
|
|---|
| 91 | begin
|
|---|
| 92 | FBlurType:= ABlurType;
|
|---|
| 93 | case ABlurType of
|
|---|
| 94 | rbNormal,rbPrecise: weightFunc:=
|
|---|
| 95 | ' float sigma = max(0.1,radius/1.8);'#10+
|
|---|
| 96 | ' float normalized = x/sigma;'#10 +
|
|---|
| 97 | ' return 1/(2.506628274631*sigma)*exp(-0.5*normalized*normalized);';
|
|---|
| 98 | rbCorona: weightFunc := 'return max(0, 1-abs(x-radius));';
|
|---|
| 99 | rbFast: weightFunc := 'return max(0,radius+1-x);';
|
|---|
| 100 | else {rbBox,rbDisk}
|
|---|
| 101 | weightFunc := 'if (x <= radius) return 1; else return max(0,radius+1-x);';
|
|---|
| 102 | end;
|
|---|
| 103 |
|
|---|
| 104 | inherited Create(ACanvas,
|
|---|
| 105 | 'void main(void) {'#10 +
|
|---|
| 106 | ' gl_Position = gl_ProjectionMatrix * gl_Vertex;'#10 +
|
|---|
| 107 | ' texCoord = vec2(gl_MultiTexCoord0);'#10 +
|
|---|
| 108 | '}',
|
|---|
| 109 |
|
|---|
| 110 | 'uniform sampler2D image;'#10 +
|
|---|
| 111 | 'uniform ivec2 textureSize;'#10 +
|
|---|
| 112 | 'uniform vec2 direction;'#10 +
|
|---|
| 113 | 'uniform float radius;'#10 +
|
|---|
| 114 | 'out vec4 FragmentColor;'#10 +
|
|---|
| 115 |
|
|---|
| 116 | 'float computeWeight(float x)'#10 +
|
|---|
| 117 | '{'#10 +
|
|---|
| 118 | weightFunc + #10 +
|
|---|
| 119 | '}'#10 +
|
|---|
| 120 |
|
|---|
| 121 | 'void main(void)'#10 +
|
|---|
| 122 | '{'#10 +
|
|---|
| 123 | ' int range = int(radius+1.5);'#10 +
|
|---|
| 124 |
|
|---|
| 125 | ' float weight = computeWeight(0);'#10 +
|
|---|
| 126 | ' float totalWeight = weight;'#10 +
|
|---|
| 127 | ' FragmentColor = texture2D( image, texCoord ) * weight;'#10 +
|
|---|
| 128 |
|
|---|
| 129 | ' for (int i=1; i<=range; i++) {'#10 +
|
|---|
| 130 | ' weight = computeWeight(i);'#10 +
|
|---|
| 131 | ' FragmentColor += texture2D( image, texCoord + i*direction/textureSize ) * weight;'#10 +
|
|---|
| 132 | ' FragmentColor += texture2D( image, texCoord - i*direction/textureSize ) * weight;'#10 +
|
|---|
| 133 | ' totalWeight += 2*weight;'#10 +
|
|---|
| 134 | ' }'#10 +
|
|---|
| 135 |
|
|---|
| 136 | ' FragmentColor /= totalWeight;'#10 +
|
|---|
| 137 | '}',
|
|---|
| 138 |
|
|---|
| 139 | 'varying vec2 texCoord;', '130');
|
|---|
| 140 |
|
|---|
| 141 | FImageIndex := UniformInteger['image'];
|
|---|
| 142 | FTextureSize := UniformPoint['textureSize'];
|
|---|
| 143 | FDirection := UniformPointF['direction'];
|
|---|
| 144 | FRadius := UniformSingle['radius'];
|
|---|
| 145 |
|
|---|
| 146 | ImageIndex:= 0;
|
|---|
| 147 | Direction := PointF(1,0);
|
|---|
| 148 | TextureSize := Point(1,1);
|
|---|
| 149 | Radius := 0;
|
|---|
| 150 | end;
|
|---|
| 151 |
|
|---|
| 152 | function TBGLBlurShader.FilterBlurRadial(ATexture: IBGLTexture): IBGLTexture;
|
|---|
| 153 | var horiz: IBGLTexture;
|
|---|
| 154 | begin
|
|---|
| 155 | horiz := FilterBlurMotion(ATexture, PointF(1,0));
|
|---|
| 156 | result := FilterBlurMotion(horiz, PointF(0,1));
|
|---|
| 157 | end;
|
|---|
| 158 |
|
|---|
| 159 | function TBGLBlurShader.FilterBlurMotion(ATexture: IBGLTexture): IBGLTexture;
|
|---|
| 160 | var previousBuf,buf: TBGLCustomFrameBuffer;
|
|---|
| 161 | previousShader: TBGLCustomShader;
|
|---|
| 162 | begin
|
|---|
| 163 | previousBuf := Canvas.ActiveFrameBuffer;
|
|---|
| 164 | buf := Canvas.CreateFrameBuffer(ATexture.Width, ATexture.Height);
|
|---|
| 165 | Canvas.ActiveFrameBuffer := buf;
|
|---|
| 166 |
|
|---|
| 167 | TextureSize := Point(ATexture.Width,ATexture.Height);
|
|---|
| 168 | previousShader := Canvas.Lighting.ActiveShader;
|
|---|
| 169 | Canvas.Lighting.ActiveShader := self;
|
|---|
| 170 |
|
|---|
| 171 | ATexture.Draw(0, 0); //perform horiz blur
|
|---|
| 172 |
|
|---|
| 173 | Canvas.Lighting.ActiveShader := previousShader;
|
|---|
| 174 | Canvas.ActiveFrameBuffer := previousBuf;
|
|---|
| 175 | result := buf.MakeTextureAndFree;
|
|---|
| 176 | end;
|
|---|
| 177 |
|
|---|
| 178 | function TBGLBlurShader.FilterBlurMotion(ATexture: IBGLTexture;
|
|---|
| 179 | ADirection: TPointF): IBGLTexture;
|
|---|
| 180 | var prevDir: TPointF;
|
|---|
| 181 | begin
|
|---|
| 182 | prevDir := Direction;
|
|---|
| 183 | Direction := ADirection;
|
|---|
| 184 | result := FilterBlurMotion(ATexture);
|
|---|
| 185 | Direction := prevDir;
|
|---|
| 186 | end;
|
|---|
| 187 |
|
|---|
| 188 | procedure TBGLBlurShader.StartUse;
|
|---|
| 189 | begin
|
|---|
| 190 | inherited StartUse;
|
|---|
| 191 | FImageIndex.Update;
|
|---|
| 192 | FTextureSize.Update;
|
|---|
| 193 | FDirection.Update;
|
|---|
| 194 | FRadius.Update;
|
|---|
| 195 | end;
|
|---|
| 196 |
|
|---|
| 197 | end.
|
|---|
| 198 |
|
|---|
| 199 |
|
|---|