GLSL.ShaderCombiner.pas 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. //
  2. // The graphics engine GLScene https://github.com/glscene
  3. //
  4. unit GLSL.ShaderCombiner;
  5. (*
  6. Allows to combine shaders in different sequences.
  7. Note, that can't just take 2 random shaders and combine them, because
  8. shaders often override the objects material and vertex data with a total
  9. disregard to what existed before it. But in some cases, especially with
  10. multipass shaders, this unit does magic and allows to reuse and upgrade
  11. previously written shaders.
  12. *)
  13. interface
  14. {$I GLScene.Defines.inc}
  15. uses
  16. System.Classes,
  17. GLS.Material,
  18. GLS.Scene,
  19. GLScene.VectorGeometry,
  20. GLScene.Strings,
  21. GLS.RenderContextInfo;
  22. type
  23. (*
  24. MP - multipass, SP-singlepass, AP - anypass (single or multi)
  25. One-Two or Two-One determines the order of how the shaders should be applied
  26. For example, sctTwoMPOneSP means that first one will be applied Shader Two,
  27. which can be a multipass shader, then Shader One is applied, which should be
  28. a singlepass shader.
  29. sctOneMPTwoSP and sctTwoMPOneSP modes are actualy quite Str@nge,
  30. because... well look at the code yourself
  31. TODO: Add more modes here, including sctOneAPTwoAP, which should be the
  32. default one.
  33. *)
  34. TGLShaderCombinerType = (sctOneSPTwoAP, sctTwoSPOneAP,
  35. sctOneMPTwoSP, sctTwoMPOneSP);
  36. TGLCustomShaderCombiner = class(TGLShader)
  37. private
  38. FCurrentPass: Integer;
  39. FCombinerType: TGLShaderCombinerType;
  40. FShaderOne: TGLShader;
  41. FShaderTwo: TGLShader;
  42. procedure SetShaderOne(const Value: TGLShader);
  43. procedure SetShaderTwo(const Value: TGLShader);
  44. protected
  45. procedure DoApply(var rci : TGLRenderContextInfo; Sender : TObject); override;
  46. function DoUnApply(var rci: TGLRenderContextInfo): Boolean; override;
  47. procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  48. property CombinerType: TGLShaderCombinerType read FCombinerType write FCombinerType default sctOneSPTwoAP;
  49. property ShaderOne: TGLShader read FShaderOne write SetShaderOne;
  50. property ShaderTwo: TGLShader read FShaderTwo write SetShaderTwo;
  51. property CurrentPass : Integer read FCurrentPass stored False;
  52. public
  53. constructor Create(AOwner: TComponent); override;
  54. function ShaderSupported: Boolean; override;
  55. procedure Assign(Source: TPersistent); override;
  56. end;
  57. TGLShaderCombiner = class(TGLCustomShaderCombiner)
  58. published
  59. property CombinerType;
  60. property ShaderOne;
  61. property ShaderTwo;
  62. property ShaderStyle;
  63. end;
  64. //---------------------------------------------
  65. implementation
  66. //---------------------------------------------
  67. //-----------------------------
  68. // TGLCustomShaderCombiner
  69. //-----------------------------
  70. procedure TGLCustomShaderCombiner.Assign(Source: TPersistent);
  71. begin
  72. inherited;
  73. if Source is TGLCustomShaderCombiner then
  74. begin
  75. SetShaderOne(TGLCustomShaderCombiner(Source).FShaderOne);
  76. SetShaderTwo(TGLCustomShaderCombiner(Source).FShaderTwo);
  77. end;
  78. end;
  79. constructor TGLCustomShaderCombiner.Create(AOwner: TComponent);
  80. begin
  81. inherited;
  82. FCombinerType := sctOneSPTwoAP;
  83. end;
  84. procedure TGLCustomShaderCombiner.DoApply(var rci: TGLRenderContextInfo;
  85. Sender: TObject);
  86. begin
  87. if (csDesigning in ComponentState) then Exit;
  88. Assert((FShaderOne <> nil) and (FShaderTwo <> nil));
  89. FCurrentPass:=1;
  90. case FCombinerType of
  91. sctOneMPTwoSP:
  92. begin
  93. FShaderOne.Apply(rci, Self);
  94. FShaderTwo.Apply(rci, Self);
  95. end;
  96. sctTwoMPOneSP:
  97. begin
  98. FShaderTwo.Apply(rci, Self);
  99. FShaderOne.Apply(rci, Self);
  100. end;
  101. sctOneSPTwoAP:
  102. begin
  103. FShaderOne.Apply(rci, Self);
  104. end;
  105. sctTwoSPOneAP:
  106. begin
  107. FShaderTwo.Apply(rci, Self);
  108. end;
  109. else
  110. Assert(False, strErrorEx + strUnknownType);
  111. end;
  112. end;
  113. function TGLCustomShaderCombiner.DoUnApply(var rci: TGLRenderContextInfo): Boolean;
  114. begin
  115. case FCombinerType of
  116. sctOneMPTwoSP:
  117. begin
  118. if FShaderOne.UnApply(rci) then
  119. Result := True
  120. else
  121. Result := FShaderTwo.UnApply(rci);
  122. end;
  123. sctTwoMPOneSP:
  124. begin
  125. if FShaderTwo.UnApply(rci) then
  126. Result := True
  127. else
  128. Result := FShaderOne.UnApply(rci);
  129. end;
  130. sctOneSPTwoAP:
  131. begin
  132. if FCurrentPass = 1 then
  133. begin
  134. FShaderOne.UnApply(rci);
  135. FShaderTwo.Apply(rci, Self);
  136. Result := True;
  137. end
  138. else
  139. Result := FShaderTwo.UnApply(rci);
  140. end;
  141. sctTwoSPOneAP:
  142. begin
  143. if FCurrentPass = 1 then
  144. begin
  145. FShaderTwo.UnApply(rci);
  146. FShaderOne.Apply(rci, Self);
  147. Result := True;
  148. end
  149. else
  150. Result := FShaderOne.UnApply(rci);
  151. end;
  152. else
  153. begin
  154. Result := False;
  155. Assert(False, strErrorEx + strUnknownType);
  156. end;
  157. end;
  158. Inc(FCurrentPass);
  159. end;
  160. procedure TGLCustomShaderCombiner.Notification(AComponent: TComponent;
  161. Operation: TOperation);
  162. begin
  163. inherited;
  164. if Operation = opRemove then
  165. begin
  166. if AComponent = FShaderOne then
  167. FShaderOne := nil
  168. else if AComponent = FShaderTwo then
  169. FShaderTwo := nil;
  170. end;
  171. end;
  172. procedure TGLCustomShaderCombiner.SetShaderOne(const Value: TGLShader);
  173. begin
  174. if FShaderOne <> nil then
  175. FShaderOne.RemoveFreeNotification(Self);
  176. FShaderOne := Value;
  177. if FShaderOne <> nil then
  178. FShaderOne.FreeNotification(Self);
  179. end;
  180. procedure TGLCustomShaderCombiner.SetShaderTwo(const Value: TGLShader);
  181. begin
  182. if FShaderTwo <> nil then
  183. FShaderTwo.RemoveFreeNotification(Self);
  184. FShaderTwo := Value;
  185. if FShaderTwo <> nil then
  186. FShaderTwo.FreeNotification(Self);
  187. end;
  188. function TGLCustomShaderCombiner.ShaderSupported: Boolean;
  189. begin
  190. Result := (FShaderOne <> nil) and (FShaderTwo <> nil) and
  191. FShaderOne.ShaderSupported and FShaderTwo.ShaderSupported;
  192. end;
  193. //-----------------------------------
  194. initialization
  195. //-----------------------------------
  196. RegisterClasses([TGLCustomShaderCombiner, TGLShaderCombiner]);
  197. end.