2
// This unit is part of the GLScene Engine https://github.com/glscene
5
A shader that applies cel shading through a vertex program
6
and shade definition texture.
9
23/08/10 - Yar - Upgraded program hadles
10
22/04/10 - Yar - Fixes after GLState revision
11
05/03/10 - DanB - More state added to TGLStateCache
12
22/01/10 - Yar - Added bmp32.Blank:=false for memory allocation
13
06/06/07 - DaStr - Added GLColor to uses (BugtrackerID = 1732211)
14
31/03/07 - DaStr - Added $I GLScene.inc
15
21/03/07 - DaStr - Added explicit pointer dereferencing
16
(thanks Burkhard Carstens) (Bugtracker ID = 1678644)
17
25/02/07 - DaStr - Moved registration to GLSceneRegister.pas
18
28/09/04 - SG - Vertex program now uses ARB_position_invariant option.
19
09/06/04 - SG - Added OutlineColor, vertex programs now use GL state.
20
28/05/04 - SG - Creation.
30
Classes, SysUtils, GLTexture, GLContext, GLGraphics, GLUtils,
31
GLVectorGeometry, OpenGLTokens, GLColor, GLRenderContextInfo,
32
GLMaterial, GLState, GLTextureFormat;
37
{ Cel shading options.
38
csoOutlines: Render a second outline pass.
39
csoTextured: Allows for a primary texture that the cel shading
40
is modulated with and forces the shade definition
41
to render as a second texture. }
42
TGLCelShaderOption = (csoOutlines, csoTextured, csoNoBuildShadeTexture);
43
TGLCelShaderOptions = set of TGLCelShaderOption;
45
// TGLCelShaderGetIntensity
47
// An event for user defined cel intensity.
48
TGLCelShaderGetIntensity = procedure(Sender: TObject; var intensity: Byte) of
53
{ A generic cel shader. }
54
TGLCelShader = class(TGLShader)
56
FOutlineWidth: Single;
57
FCelShaderOptions: TGLCelShaderOptions;
58
FVPHandle: TGLARBVertexProgramHandle;
59
FShadeTexture: TGLTexture;
60
FOnGetIntensity: TGLCelShaderGetIntensity;
62
FUnApplyShadeTexture: Boolean;
63
FOutlineColor: TGLColor;
65
procedure SetCelShaderOptions(const val: TGLCelShaderOptions);
66
procedure SetOutlineWidth(const val: Single);
67
procedure SetOutlineColor(const val: TGLColor);
68
procedure BuildShadeTexture;
69
procedure Loaded; override;
70
function GenerateVertexProgram: string;
73
constructor Create(AOwner: TComponent); override;
74
destructor Destroy; override;
76
procedure DoApply(var rci: TGLRenderContextInfo; Sender: TObject); override;
77
function DoUnApply(var rci: TGLRenderContextInfo): Boolean; override;
79
property ShadeTexture: TGLTexture read FShadeTexture;
82
property CelShaderOptions: TGLCelShaderOptions read FCelShaderOptions write
84
property OutlineColor: TGLColor read FOutlineColor write SetOutlineColor;
85
property OutlineWidth: Single read FOutlineWidth write SetOutlineWidth;
86
property OnGetIntensity: TGLCelShaderGetIntensity read FOnGetIntensity write
90
// ------------------------------------------------------------------
91
// ------------------------------------------------------------------
92
// ------------------------------------------------------------------
94
// ------------------------------------------------------------------
95
// ------------------------------------------------------------------
96
// ------------------------------------------------------------------
99
// ------------------ TGLCelShader ------------------
105
constructor TGLCelShader.Create(AOwner: TComponent);
110
FCelShaderOptions := [csoOutlines];
111
FShadeTexture := TGLTexture.Create(Self);
112
with FShadeTexture do
115
MinFilter := miNearest;
116
MagFilter := maNearest;
117
TextureWrap := twNone;
118
TextureMode := tmModulate;
121
FOutlineColor := TGLColor.Create(Self);
122
FOutlineColor.OnNotifyChange := NotifyChange;
123
FOutlineColor.Initialize(clrBlack);
125
ShaderStyle := ssLowLevel;
127
FVPHandle := TGLARBVertexProgramHandle.Create;
133
destructor TGLCelShader.Destroy;
144
procedure TGLCelShader.Loaded;
153
procedure TGLCelShader.BuildShadeTexture;
159
if csoNoBuildShadeTexture in FCelShaderOptions then
162
with FShadeTexture do
164
ImageClassName := 'TGLBlankImage';
165
TGLBlankImage(Image).Width := 128;
166
TGLBlankImage(Image).Height := 2;
169
bmp32 := FShadeTexture.Image.GetBitmap32;
170
bmp32.Blank := false;
171
for i := 0 to bmp32.Width - 1 do
173
intensity := i * (256 div bmp32.Width);
175
if Assigned(FOnGetIntensity) then
176
FOnGetIntensity(Self, intensity)
179
if intensity > 230 then
181
else if intensity > 150 then
183
else if intensity > 100 then
184
intensity := intensity + 50
189
bmp32.Data^[i].r := intensity;
190
bmp32.Data^[i].g := intensity;
191
bmp32.Data^[i].b := intensity;
192
bmp32.Data^[i].a := 1;
193
bmp32.Data^[i + bmp32.Width] := bmp32.Data^[i];
197
// GenerateVertexProgram
200
function TGLCelShader.GenerateVertexProgram: string;
204
VP := TStringList.Create;
206
VP.Add('!!ARBvp1.0');
207
VP.Add('OPTION ARB_position_invariant;');
209
VP.Add('PARAM mvinv[4] = { state.matrix.modelview.inverse };');
210
VP.Add('PARAM lightPos = program.local[0];');
211
VP.Add('TEMP temp, light, normal;');
213
VP.Add(' DP4 light.x, mvinv[0], lightPos;');
214
VP.Add(' DP4 light.y, mvinv[1], lightPos;');
215
VP.Add(' DP4 light.z, mvinv[2], lightPos;');
216
VP.Add(' ADD light, light, -vertex.position;');
217
VP.Add(' DP3 temp.x, light, light;');
218
VP.Add(' RSQ temp.x, temp.x;');
219
VP.Add(' MUL light, temp.x, light;');
221
VP.Add(' DP3 temp, vertex.normal, vertex.normal;');
222
VP.Add(' RSQ temp.x, temp.x;');
223
VP.Add(' MUL normal, temp.x, vertex.normal;');
225
VP.Add(' MOV result.color, state.material.diffuse;');
227
if csoTextured in FCelShaderOptions then
229
VP.Add(' MOV result.texcoord[0], vertex.texcoord[0];');
230
VP.Add(' DP3 result.texcoord[1].x, normal, light;');
234
VP.Add(' DP3 result.texcoord[0].x, normal, light;');
246
procedure TGLCelShader.DoApply(var rci: TGLRenderContextInfo; Sender: TObject);
250
if (csDesigning in ComponentState) then
253
FVPHandle.AllocateHandle;
254
if FVPHandle.IsDataNeedUpdate then
256
FVPHandle.LoadARBProgram(GenerateVertexProgram);
257
Enabled := FVPHandle.Ready;
258
FVPHandle.NotifyDataUpdated;
263
rci.GLStates.Disable(stLighting);
264
GL.GetLightfv(GL_LIGHT0, GL_POSITION, @light.V[0]);
267
GL.ProgramLocalParameter4fv(GL_VERTEX_PROGRAM_ARB, 0, @light.V[0]);
269
if (csoTextured in FCelShaderOptions) then
270
FShadeTexture.ApplyAsTexture2(rci, nil)
272
FShadeTexture.Apply(rci);
274
FOutlinePass := csoOutlines in FCelShaderOptions;
275
FUnApplyShadeTexture := True;
281
function TGLCelShader.DoUnApply(var rci: TGLRenderContextInfo): Boolean;
284
if (csDesigning in ComponentState) then
289
if FUnApplyShadeTexture then
291
if (csoTextured in FCelShaderOptions) then
292
FShadeTexture.UnApplyAsTexture2(rci, false)
294
FShadeTexture.UnApply(rci);
295
FUnApplyShadeTexture := False;
302
ActiveTextureEnabled[ttTexture2D] := False;
304
Enable(stLineSmooth);
305
Disable(stLineStipple);
308
PolygonMode := pmLines;
309
LineWidth := FOutlineWidth;
310
CullFaceMode := cmFront;
311
LineSmoothHint := hintNicest;
312
SetBlendFunc(bfSrcAlpha, bfOneMinusSrcAlpha);
313
DepthFunc := cfLEqual;
314
GL.Color4fv(FOutlineColor.AsAddress);
317
FOutlinePass := False;
323
rci.GLStates.PolygonMode := pmFill;
324
rci.GLStates.CullFaceMode := cmBack;
325
rci.GLStates.DepthFunc := cfLEqual;
330
// SetCelShaderOptions
333
procedure TGLCelShader.SetCelShaderOptions(const val: TGLCelShaderOptions);
335
if val <> FCelShaderOptions then
337
FCelShaderOptions := val;
339
FVPHandle.NotifyChangesOfData;
347
procedure TGLCelShader.SetOutlineWidth(const val: Single);
349
if val <> FOutlineWidth then
351
FOutlineWidth := val;
359
procedure TGLCelShader.SetOutlineColor(const val: TGLColor);
361
if val <> FOutlineColor then
363
FOutlineColor.Assign(val);