GLHiddenLineShader.pas 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  1. //
  2. // This unit is part of the GLScene Engine, http://glscene.org
  3. //
  4. {
  5. A shader that renders hidden (back-faced) lines differently from visible
  6. (front) lines. Polygon offset is used to displace fragments depths a little
  7. so that there is no z-fighting in rendering the same geometry multiple times.
  8. }
  9. unit GLHiddenLineShader;
  10. interface
  11. {$I GLScene.inc}
  12. uses
  13. System.Classes,
  14. OpenGLTokens,
  15. GLScene,
  16. GLColor,
  17. GLMaterial,
  18. GLBaseClasses,
  19. GLRenderContextInfo,
  20. GLState,
  21. GLContext;
  22. type
  23. TGLLineSettings = class(TGLUpdateAbleObject)
  24. private
  25. FColor: TGLColor;
  26. FWidth: Single;
  27. FPattern: TGLushort;
  28. FForceMaterial: Boolean;
  29. procedure SetPattern(const value: TGLushort);
  30. procedure SetColor(const v: TGLColor);
  31. procedure SetWidth(const Value: Single);
  32. procedure SetForceMaterial(v: boolean);
  33. public
  34. constructor Create(AOwner: TPersistent); override;
  35. destructor Destroy; override;
  36. procedure Apply(var rci: TGLRenderContextInfo);
  37. procedure UnApply(var rci: TGLRenderContextInfo);
  38. published
  39. property Width: Single read FWidth write SetWidth;
  40. property Color: TGLColor read FColor write SetColor;
  41. property Pattern: TGLushort read FPattern write SetPattern default $FFFF;
  42. {Set ForceMaterial to true to enforce the application of the line settings
  43. for objects that sets their own color, line width and pattern. }
  44. property ForceMaterial: Boolean read FForceMaterial write SetForceMaterial
  45. default false;
  46. end;
  47. TGLHiddenLineShader = class(TGLShader)
  48. private
  49. FPassCount: integer;
  50. FLineSmooth: Boolean;
  51. FSolid: Boolean;
  52. FBackGroundColor: TGLColor;
  53. FFrontLine: TGLLineSettings;
  54. FBackLine: TGLLineSettings;
  55. FLighting: Boolean;
  56. FShadeModel: TGLShadeModel;
  57. procedure SetlineSmooth(v: boolean);
  58. procedure SetSolid(v: boolean);
  59. procedure SetBackgroundColor(AColor: TGLColor);
  60. procedure SetLighting(v: boolean);
  61. procedure SetShadeModel(const val: TGLShadeModel);
  62. protected
  63. procedure DoApply(var rci: TGLRenderContextInfo; Sender: TObject); override;
  64. function DoUnApply(var rci: TGLRenderContextInfo): Boolean; override;
  65. public
  66. constructor Create(AOwner: TComponent); override;
  67. destructor Destroy; override;
  68. published
  69. property FrontLine: TGLLineSettings read FFrontLine write FFrontLine;
  70. property BackLine: TGLLineSettings read FBackLine write FBackLine;
  71. {Line smoothing control }
  72. property LineSmooth: Boolean read FlineSmooth write SetlineSmooth default
  73. false;
  74. {Solid controls if you can see through the front-line wireframe. }
  75. property Solid: Boolean read FSolid write SetSolid default false;
  76. {Color used for solid fill. }
  77. property BackgroundColor: TGLColor read FBackgroundColor write
  78. SetBackgroundColor;
  79. {When Solid is True, determines if lighting or background color is used. }
  80. property SurfaceLit: Boolean read FLighting write SetLighting default true;
  81. {Shade model.
  82. Default is "Smooth". }
  83. property ShadeModel: TGLShadeModel read FShadeModel write SetShadeModel
  84. default smDefault;
  85. end;
  86. // ------------------------------------------------------------------
  87. // ------------------------------------------------------------------
  88. // ------------------------------------------------------------------
  89. implementation
  90. // ------------------
  91. // ------------------ TGLLineSettings ------------------
  92. // ------------------
  93. constructor TGLLineSettings.Create(AOwner: TPersistent);
  94. begin
  95. inherited;
  96. FColor := TGLColor.Create(Self);
  97. FColor.Initialize(clrGray20);
  98. FWidth := 2;
  99. Pattern := $FFFF;
  100. ForceMaterial := false;
  101. end;
  102. destructor TGLLineSettings.Destroy;
  103. begin
  104. FColor.Free;
  105. inherited;
  106. end;
  107. procedure TGLLineSettings.SetPattern(const value: TGLushort);
  108. begin
  109. if FPattern <> value then
  110. begin
  111. FPattern := Value;
  112. NotifyChange(self);
  113. end;
  114. end;
  115. procedure TGLLineSettings.SetColor(const v: TGLColor);
  116. begin
  117. FColor.Color := v.Color;
  118. NotifyChange(Self);
  119. end;
  120. procedure TGLLineSettings.SetWidth(const Value: Single);
  121. begin
  122. FWidth := Value;
  123. NotifyChange(Self);
  124. end;
  125. var
  126. IgnoreMatSave: boolean;
  127. procedure TGLLineSettings.Apply(var rci: TGLRenderContextInfo);
  128. begin
  129. rci.GLStates.LineWidth := Width;
  130. gl.Color4fv(Color.AsAddress);
  131. if Pattern <> $FFFF then
  132. begin
  133. rci.GLStates.Enable(stLineStipple);
  134. rci.GLStates.LineStippleFactor := 1;
  135. rci.GLStates.LineStipplePattern := Pattern;
  136. end
  137. else
  138. rci.GLStates.Disable(stLineStipple);
  139. if ForceMaterial then
  140. begin
  141. IgnoreMatSave := rci.ignoreMaterials;
  142. rci.ignoreMaterials := true;
  143. end;
  144. end;
  145. procedure TGLLineSettings.UnApply(var rci: TGLRenderContextInfo);
  146. begin
  147. if ForceMaterial then
  148. rci.ignoreMaterials := IgnoreMatSave;
  149. end;
  150. procedure TGLLineSettings.SetForceMaterial(v: boolean);
  151. begin
  152. if FForceMaterial <> v then
  153. begin
  154. FForceMaterial := v;
  155. NotifyChange(self);
  156. end;
  157. end;
  158. // ------------------
  159. // ------------------ TGLHiddenLineShader ------------------
  160. // ------------------
  161. constructor TGLHiddenLineShader.Create(AOwner: TComponent);
  162. begin
  163. inherited;
  164. FFrontLine := TGLLineSettings.Create(self);
  165. FBackLine := TGLLineSettings.Create(self);
  166. FSolid := false;
  167. FBackgroundColor := TGLColor.Create(Self);
  168. FBackgroundColor.Initialize(clrBtnFace);
  169. FLineSmooth := False;
  170. FLighting := true;
  171. FShadeModel := smDefault;
  172. end;
  173. destructor TGLHiddenLineShader.Destroy;
  174. begin
  175. FFrontLine.Free;
  176. FBackLine.Free;
  177. FBackgroundColor.Free;
  178. inherited;
  179. end;
  180. procedure TGLHiddenLineShader.DoApply(var rci: TGLRenderContextInfo; Sender:
  181. TObject);
  182. begin
  183. FPassCount := 1;
  184. if solid then
  185. with rci.GLStates do
  186. begin
  187. // draw filled front faces in first pass
  188. PolygonMode := pmFill;
  189. CullFaceMode := cmBack;
  190. if FLighting then
  191. begin
  192. case ShadeModel of
  193. smDefault, smSmooth: gl.ShadeModel(GL_SMOOTH);
  194. smFlat: gl.ShadeModel(GL_FLAT);
  195. end
  196. end
  197. else
  198. begin
  199. Disable(stLighting);
  200. gl.Color4fv(FBackgroundColor.AsAddress); // use background color
  201. end;
  202. // enable and adjust polygon offset
  203. Enable(stPolygonOffsetFill);
  204. end
  205. else
  206. with rci.GLStates do
  207. begin
  208. Disable(stLighting);
  209. // draw back lines in first pass
  210. FBackLine.Apply(rci);
  211. CullFaceMode := cmFront;
  212. PolygonMode := pmLines;
  213. // enable and adjust polygon offset
  214. Enable(stPolygonOffsetLine);
  215. end;
  216. rci.GLStates.SetPolygonOffset(1, 2);
  217. end;
  218. function TGLHiddenLineShader.DoUnApply(var rci: TGLRenderContextInfo): Boolean;
  219. procedure SetLineSmoothBlend;
  220. begin
  221. with rci.GLStates do
  222. begin
  223. LineStippleFactor := 1;
  224. LineStipplePattern := $FFFF;
  225. if LineSmooth then
  226. begin
  227. LineSmoothHint := hintNicest;
  228. Enable(stLineSmooth);
  229. end
  230. else
  231. Disable(stLineSmooth);
  232. if LineSmooth or (FBackLine.FColor.Alpha < 1)
  233. or (FFrontLine.FColor.Alpha < 1) then
  234. begin
  235. Enable(stBlend);
  236. SetBlendFunc(bfSrcAlpha, bfOneMinusSrcAlpha);
  237. end
  238. else
  239. Disable(stBlend);
  240. end;
  241. end;
  242. begin
  243. case FPassCount of
  244. 1:
  245. with rci.GLStates do begin
  246. // draw front line in 2nd pass
  247. FPassCount := 2;
  248. FBackLine.UnApply(rci);
  249. FFrontLine.Apply(rci);
  250. SetLineSmoothBlend;
  251. if solid and FLighting then
  252. Disable(stLighting);
  253. PolygonMode := pmLines;
  254. CullFaceMode := cmBack;
  255. if solid then
  256. rci.GLStates.Disable(stPolygonOffsetFill)
  257. else
  258. rci.GLStates.Disable(stPolygonOffsetLine);
  259. Result := True;
  260. end;
  261. 2:
  262. begin
  263. FFrontLine.UnApply(rci);
  264. rci.GLStates.PolygonMode := pmFill;
  265. Result := false;
  266. end;
  267. else
  268. Assert(False);
  269. Result := False;
  270. end;
  271. end;
  272. procedure TGLHiddenLineShader.SetBackgroundColor(AColor: TGLColor);
  273. begin
  274. FBackgroundColor.Color := AColor.Color;
  275. NotifyChange(Self);
  276. end;
  277. procedure TGLHiddenLineShader.SetlineSmooth(v: boolean);
  278. begin
  279. if FlineSmooth <> v then
  280. begin
  281. FlineSmooth := v;
  282. NotifyChange(self);
  283. end;
  284. end;
  285. procedure TGLHiddenLineShader.SetLighting(v: boolean);
  286. begin
  287. if FLighting <> v then
  288. begin
  289. FLighting := v;
  290. NotifyChange(self);
  291. end;
  292. end;
  293. procedure TGLHiddenLineShader.SetSolid(v: boolean);
  294. begin
  295. if FSolid <> v then
  296. begin
  297. FSolid := v;
  298. NotifyChange(self);
  299. end;
  300. end;
  301. procedure TGLHiddenLineShader.SetShadeModel(const val: TGLShadeModel);
  302. begin
  303. if FShadeModel <> val then
  304. begin
  305. FShadeModel := val;
  306. NotifyChange(Self);
  307. end;
  308. end;
  309. end.