GLS.ShaderHiddenLine.pas 8.5 KB

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