123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329 |
- //
- // The graphics engine GLXEngine. The unit of GXScene for Delphi
- //
- unit GXS.CelShader;
- (*
- A shader that applies cel shading through a vertex program
- and shade definition texture.
- *)
- interface
- {$I Stage.Defines.inc}
- uses
- Winapi.OpenGL,
- Winapi.OpenGLext,
- System.Classes,
- System.SysUtils,
- Stage.VectorTypes,
- Stage.VectorGeometry,
- GXS.Color,
- Stage.TextureFormat,
- GXS.Texture,
- GXS.Context,
- GXS.Graphics,
- GXS.ImageUtils,
- GXS.RenderContextInfo,
- GXS.Material,
- GXS.State;
- 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.
- *)
- TgxCelShaderOption = (csoOutlines, csoTextured, csoNoBuildShadeTexture);
- TgxCelShaderOptions = set of TgxCelShaderOption;
- // An event for user defined cel intensity.
- TgxCelShaderGetIntensity = procedure(Sender: TObject; var intensity: Byte) of
- object;
- // A generic cel shader.
- TgxCelShader = class(TgxShader)
- private
- FOutlineWidth: Single;
- FCelShaderOptions: TgxCelShaderOptions;
- FVPHandle: TgxVertexProgramHandle;
- FShadeTexture: TgxTexture;
- FOnGetIntensity: TgxCelShaderGetIntensity;
- FOutlinePass,
- FUnApplyShadeTexture: Boolean;
- FOutlineColor: TgxColor;
- protected
- procedure SetCelShaderOptions(const val: TgxCelShaderOptions);
- procedure SetOutlineWidth(const val: Single);
- procedure SetOutlineColor(const val: TgxColor);
- procedure BuildShadeTexture;
- procedure Loaded; override;
- function GenerateVertexProgram: string;
- public
- constructor Create(AOwner: TComponent); override;
- destructor Destroy; override;
- procedure DoApply(var rci: TgxRenderContextInfo; Sender: TObject); override;
- function DoUnApply(var rci: TgxRenderContextInfo): Boolean; override;
- property ShadeTexture: TgxTexture read FShadeTexture;
- published
- property CelShaderOptions: TgxCelShaderOptions read FCelShaderOptions write
- SetCelShaderOptions;
- property OutlineColor: TgxColor read FOutlineColor write SetOutlineColor;
- property OutlineWidth: Single read FOutlineWidth write SetOutlineWidth;
- property OnGetIntensity: TgxCelShaderGetIntensity read FOnGetIntensity write
- FOnGetIntensity;
- end;
- implementation // -----------------------------------------------------------
- // ------------------
- // ------------------ TgxCelShader ------------------
- // ------------------
- constructor TgxCelShader.Create(AOwner: TComponent);
- begin
- inherited;
- FOutlineWidth := 3;
- FCelShaderOptions := [csoOutlines];
- FShadeTexture := TgxTexture.Create(Self);
- with FShadeTexture do
- begin
- Enabled := True;
- MinFilter := miNearest;
- MagFilter := maNearest;
- TextureWrap := twNone;
- TextureMode := tmModulate;
- end;
- FOutlineColor := TgxColor.Create(Self);
- FOutlineColor.OnNotifyChange := NotifyChange;
- FOutlineColor.Initialize(clrBlack);
- ShaderStyle := ssLowLevel;
- FVPHandle := TgxVertexProgramHandle.Create;
- end;
- destructor TgxCelShader.Destroy;
- begin
- FVPHandle.Free;
- FShadeTexture.Free;
- FOutlineColor.Free;
- inherited;
- end;
- procedure TgxCelShader.Loaded;
- begin
- inherited;
- BuildShadeTexture;
- end;
- procedure TgxCelShader.BuildShadeTexture;
- var
- bmp32: TgxBitmap32;
- i: Integer;
- intensity: Byte;
- begin
- if csoNoBuildShadeTexture in FCelShaderOptions then
- exit;
- with FShadeTexture do
- begin
- ImageClassName := 'TgxBlankImage';
- TgxBlankImage(Image).Width := 128;
- TgxBlankImage(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 TgxCelShader.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 TgxCelShader.DoApply(var rci: TgxRenderContextInfo; Sender: TObject);
- var
- light: TVector4f;
- 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.gxStates.Disable(stLighting);
- glGetLightfv(GL_LIGHT0, GL_POSITION, @light.X);
- FVPHandle.Enable;
- FVPHandle.Bind;
- glProgramLocalParameter4fvARB(GL_VERTEX_PROGRAM_ARB, 0, @light.X);
- if (csoTextured in FCelShaderOptions) then
- FShadeTexture.ApplyAsTexture2(rci, nil)
- else
- FShadeTexture.Apply(rci);
- FOutlinePass := csoOutlines in FCelShaderOptions;
- FUnApplyShadeTexture := True;
- end;
- function TgxCelShader.DoUnApply(var rci: TgxRenderContextInfo): 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.gxStates 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;
- glColor4fv(@FOutlineColor.AsAddress^);
- Result := True;
- FOutlinePass := False;
- Exit;
- end
- else
- with rci.gxStates do
- begin
- rci.gxStates.PolygonMode := pmFill;
- rci.gxStates.CullFaceMode := cmBack;
- rci.gxStates.DepthFunc := cfLEqual;
- end;
- end;
- procedure TgxCelShader.SetCelShaderOptions(const val: TgxCelShaderOptions);
- begin
- if val <> FCelShaderOptions then
- begin
- FCelShaderOptions := val;
- BuildShadeTexture;
- FVPHandle.NotifyChangesOfData;
- NotifyChange(Self);
- end;
- end;
- procedure TgxCelShader.SetOutlineWidth(const val: Single);
- begin
- if val <> FOutlineWidth then
- begin
- FOutlineWidth := val;
- NotifyChange(Self);
- end;
- end;
- procedure TgxCelShader.SetOutlineColor(const val: TgxColor);
- begin
- if val <> FOutlineColor then
- begin
- FOutlineColor.Assign(val);
- NotifyChange(Self);
- end;
- end;
- //--------------------------------------------------------------------------
- end.
|