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 |
|
---|