| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332 |
- //
- // This unit is part of the GLScene Engine, http://glscene.org
- //
- unit GLS.ShaderCel;
- (*
- A shader that applies cel shading through a vertex program
- and shade definition texture.
- *)
- interface
- {$I GLScene.inc}
- uses
- Winapi.OpenGL,
- Winapi.OpenGLext,
- System.Classes,
- System.SysUtils,
-
- OpenGLTokens,
- GLTexture,
- GLContext,
- GLGraphics,
- GLS.Utils,
- GLVectorGeometry,
- GLColor,
- GLRenderContextInfo,
- GLMaterial,
- GLState,
- GLTextureFormat;
- type
- (*Cel shading options.
- csoOutlines: Render a second outline pass.
- csoTextured: Allows for a primary texture that the cel shading
- is modulated with and forces the shade definition
- to render as a second texture. *)
- TGLCelShaderOption = (csoOutlines, csoTextured, csoNoBuildShadeTexture);
- TGLCelShaderOptions = set of TGLCelShaderOption;
- // An event for user defined cel intensity.
- TGLCelShaderGetIntensity = procedure(Sender: TObject; var intensity: Byte) of
- object;
- // A generic cel shader.
- TGLCelShader = class(TGLShader)
- private
- FOutlineWidth: Single;
- FCelShaderOptions: TGLCelShaderOptions;
- FVPHandle: TGLARBVertexProgramHandle;
- FShadeTexture: TGLTexture;
- FOnGetIntensity: TGLCelShaderGetIntensity;
- FOutlinePass,
- FUnApplyShadeTexture: Boolean;
- FOutlineColor: TGLColor;
- protected
- procedure SetCelShaderOptions(const val: TGLCelShaderOptions);
- procedure SetOutlineWidth(const val: Single);
- procedure SetOutlineColor(const val: TGLColor);
- procedure BuildShadeTexture;
- procedure Loaded; override;
- function GenerateVertexProgram: string;
- public
- constructor Create(AOwner: TComponent); override;
- destructor Destroy; override;
- procedure DoApply(var rci: TGLRenderContextInfo; Sender: TObject); override;
- function DoUnApply(var rci: TGLRenderContextInfo): Boolean; override;
- property ShadeTexture: TGLTexture read FShadeTexture;
- published
- property CelShaderOptions: TGLCelShaderOptions read FCelShaderOptions write
- SetCelShaderOptions;
- property OutlineColor: TGLColor read FOutlineColor write SetOutlineColor;
- property OutlineWidth: Single read FOutlineWidth write SetOutlineWidth;
- property OnGetIntensity: TGLCelShaderGetIntensity read FOnGetIntensity write
- FOnGetIntensity;
- end;
- // ------------------------------------------------------------------
- implementation
- // ------------------
- // ------------------ TGLCelShader ------------------
- // ------------------
- constructor TGLCelShader.Create(AOwner: TComponent);
- begin
- inherited;
- FOutlineWidth := 3;
- FCelShaderOptions := [csoOutlines];
- FShadeTexture := TGLTexture.Create(Self);
- with FShadeTexture do
- begin
- Enabled := True;
- MinFilter := miNearest;
- MagFilter := maNearest;
- TextureWrap := twNone;
- TextureMode := tmModulate;
- end;
- FOutlineColor := TGLColor.Create(Self);
- FOutlineColor.OnNotifyChange := NotifyChange;
- FOutlineColor.Initialize(clrBlack);
- ShaderStyle := ssLowLevel;
- FVPHandle := TGLARBVertexProgramHandle.Create;
- end;
-
- destructor TGLCelShader.Destroy;
- begin
- FVPHandle.Free;
- FShadeTexture.Free;
- FOutlineColor.Free;
- inherited;
- end;
- procedure TGLCelShader.Loaded;
- begin
- inherited;
- BuildShadeTexture;
- end;
- procedure TGLCelShader.BuildShadeTexture;
- var
- bmp32: TGLBitmap32;
- i: Integer;
- intensity: Byte;
- begin
- if csoNoBuildShadeTexture in FCelShaderOptions then
- exit;
- with FShadeTexture do
- begin
- ImageClassName := 'TGLBlankImage';
- TGLBlankImage(Image).Width := 128;
- TGLBlankImage(Image).Height := 2;
- end;
- bmp32 := FShadeTexture.Image.GetBitmap32;
- bmp32.Blank := false;
- for i := 0 to bmp32.Width - 1 do
- begin
- intensity := i * (256 div bmp32.Width);
- if Assigned(FOnGetIntensity) then
- FOnGetIntensity(Self, intensity)
- else
- begin
- if intensity > 230 then
- intensity := 255
- else if intensity > 150 then
- intensity := 230
- else if intensity > 100 then
- intensity := intensity + 50
- else
- intensity := 150;
- end;
- bmp32.Data^[i].r := intensity;
- bmp32.Data^[i].g := intensity;
- bmp32.Data^[i].b := intensity;
- bmp32.Data^[i].a := 1;
- bmp32.Data^[i + bmp32.Width] := bmp32.Data^[i];
- end;
- end;
- function TGLCelShader.GenerateVertexProgram: string;
- var
- VP: TStringList;
- begin
- VP := TStringList.Create;
- VP.Add('!!ARBvp1.0');
- VP.Add('OPTION ARB_position_invariant;');
- VP.Add('PARAM mvinv[4] = { state.matrix.modelview.inverse };');
- VP.Add('PARAM lightPos = program.local[0];');
- VP.Add('TEMP temp, light, normal;');
- VP.Add(' DP4 light.x, mvinv[0], lightPos;');
- VP.Add(' DP4 light.y, mvinv[1], lightPos;');
- VP.Add(' DP4 light.z, mvinv[2], lightPos;');
- VP.Add(' ADD light, light, -vertex.position;');
- VP.Add(' DP3 temp.x, light, light;');
- VP.Add(' RSQ temp.x, temp.x;');
- VP.Add(' MUL light, temp.x, light;');
- VP.Add(' DP3 temp, vertex.normal, vertex.normal;');
- VP.Add(' RSQ temp.x, temp.x;');
- VP.Add(' MUL normal, temp.x, vertex.normal;');
- VP.Add(' MOV result.color, state.material.diffuse;');
- if csoTextured in FCelShaderOptions then
- begin
- VP.Add(' MOV result.texcoord[0], vertex.texcoord[0];');
- VP.Add(' DP3 result.texcoord[1].x, normal, light;');
- end
- else
- begin
- VP.Add(' DP3 result.texcoord[0].x, normal, light;');
- end;
- VP.Add('END');
- Result := VP.Text;
- VP.Free;
- end;
- procedure TGLCelShader.DoApply(var rci: TGLRenderContextInfo; Sender: TObject);
- var
- light: TVector;
- begin
- if (csDesigning in ComponentState) then
- exit;
- FVPHandle.AllocateHandle;
- if FVPHandle.IsDataNeedUpdate then
- begin
- FVPHandle.LoadARBProgram(GenerateVertexProgram);
- Enabled := FVPHandle.Ready;
- FVPHandle.NotifyDataUpdated;
- if not Enabled then
- Abort;
- end;
- rci.GLStates.Disable(stLighting);
- gl.GetLightfv(GL_LIGHT0, GL_POSITION, @light.X);
- FVPHandle.Enable;
- FVPHandle.Bind;
- gl.ProgramLocalParameter4fv(GL_VERTEX_PROGRAM_NV, 0, @light.X);
- if (csoTextured in FCelShaderOptions) then
- FShadeTexture.ApplyAsTexture2(rci, nil)
- else
- FShadeTexture.Apply(rci);
- FOutlinePass := csoOutlines in FCelShaderOptions;
- FUnApplyShadeTexture := True;
- end;
- function TGLCelShader.DoUnApply(var rci: TGLRenderContextInfo): Boolean;
- begin
- Result := False;
- if (csDesigning in ComponentState) then
- exit;
- FVPHandle.Disable;
- if FUnApplyShadeTexture then
- begin
- if (csoTextured in FCelShaderOptions) then
- FShadeTexture.UnApplyAsTexture2(rci, false)
- else
- FShadeTexture.UnApply(rci);
- FUnApplyShadeTexture := False;
- end;
- if FOutlinePass then
- with rci.GLStates do
- begin
- ActiveTexture := 0;
- ActiveTextureEnabled[ttTexture2D] := False;
- Enable(stBlend);
- Enable(stLineSmooth);
- Disable(stLineStipple);
- Enable(stCullFace);
- PolygonMode := pmLines;
- LineWidth := FOutlineWidth;
- CullFaceMode := cmFront;
- LineSmoothHint := hintNicest;
- SetBlendFunc(bfSrcAlpha, bfOneMinusSrcAlpha);
- DepthFunc := cfLEqual;
- gl.Color4fv(FOutlineColor.AsAddress);
- Result := True;
- FOutlinePass := False;
- Exit;
- end
- else
- with rci.GLStates do
- begin
- rci.GLStates.PolygonMode := pmFill;
- rci.GLStates.CullFaceMode := cmBack;
- rci.GLStates.DepthFunc := cfLEqual;
- end;
- end;
- procedure TGLCelShader.SetCelShaderOptions(const val: TGLCelShaderOptions);
- begin
- if val <> FCelShaderOptions then
- begin
- FCelShaderOptions := val;
- BuildShadeTexture;
- FVPHandle.NotifyChangesOfData;
- NotifyChange(Self);
- end;
- end;
- procedure TGLCelShader.SetOutlineWidth(const val: Single);
- begin
- if val <> FOutlineWidth then
- begin
- FOutlineWidth := val;
- NotifyChange(Self);
- end;
- end;
- procedure TGLCelShader.SetOutlineColor(const val: TGLColor);
- begin
- if val <> FOutlineColor then
- begin
- FOutlineColor.Assign(val);
- NotifyChange(Self);
- end;
- end;
- end.
|