2
0

GXS.CelShader.pas 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. //
  2. // The graphics engine GLXEngine. The unit of GXScene for Delphi
  3. //
  4. unit GXS.CelShader;
  5. (*
  6. A shader that applies cel shading through a vertex program
  7. and shade definition texture.
  8. *)
  9. interface
  10. {$I Stage.Defines.inc}
  11. uses
  12. Winapi.OpenGL,
  13. Winapi.OpenGLext,
  14. System.Classes,
  15. System.SysUtils,
  16. Stage.VectorTypes,
  17. Stage.VectorGeometry,
  18. GXS.Color,
  19. Stage.TextureFormat,
  20. GXS.Texture,
  21. GXS.Context,
  22. GXS.Graphics,
  23. GXS.ImageUtils,
  24. GXS.RenderContextInfo,
  25. GXS.Material,
  26. GXS.State;
  27. type
  28. (*
  29. Cel shading options.
  30. csoOutlines: Render a second outline pass.
  31. csoTextured: Allows for a primary texture that the cel shading
  32. is modulated with and forces the shade definition
  33. to render as a second texture.
  34. *)
  35. TgxCelShaderOption = (csoOutlines, csoTextured, csoNoBuildShadeTexture);
  36. TgxCelShaderOptions = set of TgxCelShaderOption;
  37. // An event for user defined cel intensity.
  38. TgxCelShaderGetIntensity = procedure(Sender: TObject; var intensity: Byte) of
  39. object;
  40. // A generic cel shader.
  41. TgxCelShader = class(TgxShader)
  42. private
  43. FOutlineWidth: Single;
  44. FCelShaderOptions: TgxCelShaderOptions;
  45. FVPHandle: TgxVertexProgramHandle;
  46. FShadeTexture: TgxTexture;
  47. FOnGetIntensity: TgxCelShaderGetIntensity;
  48. FOutlinePass,
  49. FUnApplyShadeTexture: Boolean;
  50. FOutlineColor: TgxColor;
  51. protected
  52. procedure SetCelShaderOptions(const val: TgxCelShaderOptions);
  53. procedure SetOutlineWidth(const val: Single);
  54. procedure SetOutlineColor(const val: TgxColor);
  55. procedure BuildShadeTexture;
  56. procedure Loaded; override;
  57. function GenerateVertexProgram: string;
  58. public
  59. constructor Create(AOwner: TComponent); override;
  60. destructor Destroy; override;
  61. procedure DoApply(var rci: TgxRenderContextInfo; Sender: TObject); override;
  62. function DoUnApply(var rci: TgxRenderContextInfo): Boolean; override;
  63. property ShadeTexture: TgxTexture read FShadeTexture;
  64. published
  65. property CelShaderOptions: TgxCelShaderOptions read FCelShaderOptions write
  66. SetCelShaderOptions;
  67. property OutlineColor: TgxColor read FOutlineColor write SetOutlineColor;
  68. property OutlineWidth: Single read FOutlineWidth write SetOutlineWidth;
  69. property OnGetIntensity: TgxCelShaderGetIntensity read FOnGetIntensity write
  70. FOnGetIntensity;
  71. end;
  72. implementation // -----------------------------------------------------------
  73. // ------------------
  74. // ------------------ TgxCelShader ------------------
  75. // ------------------
  76. constructor TgxCelShader.Create(AOwner: TComponent);
  77. begin
  78. inherited;
  79. FOutlineWidth := 3;
  80. FCelShaderOptions := [csoOutlines];
  81. FShadeTexture := TgxTexture.Create(Self);
  82. with FShadeTexture do
  83. begin
  84. Enabled := True;
  85. MinFilter := miNearest;
  86. MagFilter := maNearest;
  87. TextureWrap := twNone;
  88. TextureMode := tmModulate;
  89. end;
  90. FOutlineColor := TgxColor.Create(Self);
  91. FOutlineColor.OnNotifyChange := NotifyChange;
  92. FOutlineColor.Initialize(clrBlack);
  93. ShaderStyle := ssLowLevel;
  94. FVPHandle := TgxVertexProgramHandle.Create;
  95. end;
  96. destructor TgxCelShader.Destroy;
  97. begin
  98. FVPHandle.Free;
  99. FShadeTexture.Free;
  100. FOutlineColor.Free;
  101. inherited;
  102. end;
  103. procedure TgxCelShader.Loaded;
  104. begin
  105. inherited;
  106. BuildShadeTexture;
  107. end;
  108. procedure TgxCelShader.BuildShadeTexture;
  109. var
  110. bmp32: TgxBitmap32;
  111. i: Integer;
  112. intensity: Byte;
  113. begin
  114. if csoNoBuildShadeTexture in FCelShaderOptions then
  115. exit;
  116. with FShadeTexture do
  117. begin
  118. ImageClassName := 'TgxBlankImage';
  119. TgxBlankImage(Image).Width := 128;
  120. TgxBlankImage(Image).Height := 2;
  121. end;
  122. bmp32 := FShadeTexture.Image.GetBitmap32;
  123. bmp32.Blank := false;
  124. for i := 0 to bmp32.Width - 1 do
  125. begin
  126. intensity := i * (256 div bmp32.Width);
  127. if Assigned(FOnGetIntensity) then
  128. FOnGetIntensity(Self, intensity)
  129. else
  130. begin
  131. if intensity > 230 then
  132. intensity := 255
  133. else if intensity > 150 then
  134. intensity := 230
  135. else if intensity > 100 then
  136. intensity := intensity + 50
  137. else
  138. intensity := 150;
  139. end;
  140. bmp32.Data^[i].r := intensity;
  141. bmp32.Data^[i].g := intensity;
  142. bmp32.Data^[i].b := intensity;
  143. bmp32.Data^[i].a := 1;
  144. bmp32.Data^[i + bmp32.Width] := bmp32.Data^[i];
  145. end;
  146. end;
  147. function TgxCelShader.GenerateVertexProgram: string;
  148. var
  149. VP: TStringList;
  150. begin
  151. VP := TStringList.Create;
  152. VP.Add('!!ARBvp1.0');
  153. VP.Add('OPTION ARB_position_invariant;');
  154. VP.Add('PARAM mvinv[4] = { state.matrix.modelview.inverse };');
  155. VP.Add('PARAM lightPos = program.local[0];');
  156. VP.Add('TEMP temp, light, normal;');
  157. VP.Add(' DP4 light.x, mvinv[0], lightPos;');
  158. VP.Add(' DP4 light.y, mvinv[1], lightPos;');
  159. VP.Add(' DP4 light.z, mvinv[2], lightPos;');
  160. VP.Add(' ADD light, light, -vertex.position;');
  161. VP.Add(' DP3 temp.x, light, light;');
  162. VP.Add(' RSQ temp.x, temp.x;');
  163. VP.Add(' MUL light, temp.x, light;');
  164. VP.Add(' DP3 temp, vertex.normal, vertex.normal;');
  165. VP.Add(' RSQ temp.x, temp.x;');
  166. VP.Add(' MUL normal, temp.x, vertex.normal;');
  167. VP.Add(' MOV result.color, state.material.diffuse;');
  168. if csoTextured in FCelShaderOptions then
  169. begin
  170. VP.Add(' MOV result.texcoord[0], vertex.texcoord[0];');
  171. VP.Add(' DP3 result.texcoord[1].x, normal, light;');
  172. end
  173. else
  174. begin
  175. VP.Add(' DP3 result.texcoord[0].x, normal, light;');
  176. end;
  177. VP.Add('END');
  178. Result := VP.Text;
  179. VP.Free;
  180. end;
  181. procedure TgxCelShader.DoApply(var rci: TgxRenderContextInfo; Sender: TObject);
  182. var
  183. light: TVector4f;
  184. begin
  185. if (csDesigning in ComponentState) then
  186. exit;
  187. FVPHandle.AllocateHandle;
  188. if FVPHandle.IsDataNeedUpdate then
  189. begin
  190. FVPHandle.LoadARBProgram(GenerateVertexProgram);
  191. Enabled := FVPHandle.Ready;
  192. FVPHandle.NotifyDataUpdated;
  193. if not Enabled then
  194. Abort;
  195. end;
  196. rci.gxStates.Disable(stLighting);
  197. glGetLightfv(GL_LIGHT0, GL_POSITION, @light.X);
  198. FVPHandle.Enable;
  199. FVPHandle.Bind;
  200. glProgramLocalParameter4fvARB(GL_VERTEX_PROGRAM_ARB, 0, @light.X);
  201. if (csoTextured in FCelShaderOptions) then
  202. FShadeTexture.ApplyAsTexture2(rci, nil)
  203. else
  204. FShadeTexture.Apply(rci);
  205. FOutlinePass := csoOutlines in FCelShaderOptions;
  206. FUnApplyShadeTexture := True;
  207. end;
  208. function TgxCelShader.DoUnApply(var rci: TgxRenderContextInfo): Boolean;
  209. begin
  210. Result := False;
  211. if (csDesigning in ComponentState) then
  212. exit;
  213. FVPHandle.Disable;
  214. if FUnApplyShadeTexture then
  215. begin
  216. if (csoTextured in FCelShaderOptions) then
  217. FShadeTexture.UnApplyAsTexture2(rci, false)
  218. else
  219. FShadeTexture.UnApply(rci);
  220. FUnApplyShadeTexture := False;
  221. end;
  222. if FOutlinePass then
  223. with rci.gxStates do
  224. begin
  225. ActiveTexture := 0;
  226. ActiveTextureEnabled[ttTexture2D] := False;
  227. Enable(stBlend);
  228. Enable(stLineSmooth);
  229. Disable(stLineStipple);
  230. Enable(stCullFace);
  231. PolygonMode := pmLines;
  232. LineWidth := FOutlineWidth;
  233. CullFaceMode := cmFront;
  234. LineSmoothHint := hintNicest;
  235. SetBlendFunc(bfSrcAlpha, bfOneMinusSrcAlpha);
  236. DepthFunc := cfLEqual;
  237. glColor4fv(@FOutlineColor.AsAddress^);
  238. Result := True;
  239. FOutlinePass := False;
  240. Exit;
  241. end
  242. else
  243. with rci.gxStates do
  244. begin
  245. rci.gxStates.PolygonMode := pmFill;
  246. rci.gxStates.CullFaceMode := cmBack;
  247. rci.gxStates.DepthFunc := cfLEqual;
  248. end;
  249. end;
  250. procedure TgxCelShader.SetCelShaderOptions(const val: TgxCelShaderOptions);
  251. begin
  252. if val <> FCelShaderOptions then
  253. begin
  254. FCelShaderOptions := val;
  255. BuildShadeTexture;
  256. FVPHandle.NotifyChangesOfData;
  257. NotifyChange(Self);
  258. end;
  259. end;
  260. procedure TgxCelShader.SetOutlineWidth(const val: Single);
  261. begin
  262. if val <> FOutlineWidth then
  263. begin
  264. FOutlineWidth := val;
  265. NotifyChange(Self);
  266. end;
  267. end;
  268. procedure TgxCelShader.SetOutlineColor(const val: TgxColor);
  269. begin
  270. if val <> FOutlineColor then
  271. begin
  272. FOutlineColor.Assign(val);
  273. NotifyChange(Self);
  274. end;
  275. end;
  276. //--------------------------------------------------------------------------
  277. end.