You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

264 lines
10 KiB

  1. unit uengShaderGenerator;
  2. {$mode objfpc}{$H+}
  3. {$I uengShaderFile.inc}
  4. interface
  5. uses
  6. Classes, SysUtils,
  7. uengShaderPart, uengShaderFileTypes, uengShaderFileParser, uengShaderPartScope,
  8. uengShaderPartKeyValuePair, uengShaderGeneratorArgs;
  9. type
  10. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  11. TengShaderGenerator = class(TengShaderPartScope)
  12. { Code Loading & Storage }
  13. private
  14. fPropertyMap: TengShaderPartPropertyMap;
  15. function GetPropertyByIndex(const aIndex: Integer): Variant;
  16. function GetPropertyByName(const aName: String): Variant;
  17. function GetPropertyCount: Integer;
  18. function GetPropertyNames(const aIndex: Integer): String;
  19. procedure SetPropertyByIndex(const aIndex: Integer; aValue: Variant);
  20. procedure SetPropertyByName(const aName: String; aValue: Variant);
  21. protected
  22. procedure AddProperty(const aProp: TengShaderPartProperty; const aShowWarning: Boolean = true);
  23. procedure CopyProperties(const aGen: TengShaderGenerator);
  24. procedure UpdateProperties; virtual;
  25. function ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; override;
  26. public
  27. property PropertyByName [const aName: String]: Variant read GetPropertyByName write SetPropertyByName;
  28. property PropertyByIndex[const aIndex: Integer]: Variant read GetPropertyByIndex write SetPropertyByIndex;
  29. property PropertyNames [const aIndex: Integer]: String read GetPropertyNames;
  30. property PropertyCount: Integer read GetPropertyCount;
  31. function TryGetProperty(const aName: String; out aValue: Variant): Boolean;
  32. function TrySetProperty(const aName: String; const aValue: Variant): Boolean;
  33. procedure ListProperties(const aPropertyNames: TStrings);
  34. { Generate Shader Code }
  35. public
  36. procedure GenerateCode(const aCode: TengShaderCode);
  37. { General }
  38. public
  39. constructor Create(const aParent: TengShaderPart); override;
  40. destructor Destroy; override;
  41. end;
  42. implementation
  43. uses
  44. uengShaderFile, uengShaderFileHelper, uengShaderPartProc, uengShaderPartParameter;
  45. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  46. //TengShaderGenerator///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  47. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  48. function TengShaderGenerator.GetPropertyByIndex(const aIndex: Integer): Variant;
  49. begin
  50. result := fPropertyMap.ValueAt[aIndex].Value;
  51. end;
  52. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  53. function TengShaderGenerator.GetPropertyByName(const aName: String): Variant;
  54. var
  55. l: TengShaderPartPropertyList;
  56. begin
  57. l := fPropertyMap[aName];
  58. if not Assigned(l) then
  59. EengUnknownIdentifier.Create(aName, self);
  60. result := l.Value;
  61. end;
  62. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  63. function TengShaderGenerator.GetPropertyCount: Integer;
  64. begin
  65. result := fPropertyMap.Count;
  66. end;
  67. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  68. function TengShaderGenerator.GetPropertyNames(const aIndex: Integer): String;
  69. begin
  70. result := fPropertyMap.KeyValuePairs[aIndex].Key;
  71. end;
  72. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  73. procedure TengShaderGenerator.SetPropertyByIndex(const aIndex: Integer; aValue: Variant);
  74. begin
  75. fPropertyMap.ValueAt[aIndex].Value := aValue;
  76. end;
  77. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  78. procedure TengShaderGenerator.SetPropertyByName(const aName: String; aValue: Variant);
  79. var
  80. l: TengShaderPartPropertyList;
  81. begin
  82. l := fPropertyMap[aName];
  83. if not Assigned(l) then
  84. raise EengUnknownIdentifier.Create(aName, self);
  85. l.Value := aValue;
  86. end;
  87. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  88. procedure TengShaderGenerator.AddProperty(const aProp: TengShaderPartProperty; const aShowWarning: Boolean);
  89. var
  90. i: Integer;
  91. l: TengShaderPartPropertyList;
  92. p: TengShaderPartProperty;
  93. s: String;
  94. begin
  95. i := -1;
  96. l := fPropertyMap[aProp.Name];
  97. if Assigned(l) then begin
  98. i := l.IndexOf(aProp);
  99. if aShowWarning and (i >= 0) then begin
  100. p := l.Last;
  101. s := Format('use of duplicate identifier: %s (%s %d:%d)', [aProp.Name, aProp.Filename, aProp.Line + 1, aProp.Col]) + sLineBreak +
  102. 'previously declared here:' + sLineBreak +
  103. Format(' %s %d:%d', [p.Filename, p.Line + 1, p.Col]) + sLineBreak;
  104. LogMsg(llWarning, s);
  105. end;
  106. end else begin
  107. l := TengShaderPartPropertyList.Create;
  108. fPropertyMap.Add(aProp.Name, l);
  109. end;
  110. if (i < 0) then begin
  111. l.Add(aProp);
  112. if (aProp.Value <> Unassigned) then
  113. l.Value := aProp.Value;
  114. end;
  115. end;
  116. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  117. procedure TengShaderGenerator.CopyProperties(const aGen: TengShaderGenerator);
  118. var
  119. l: TengShaderPartPropertyList;
  120. p: TengShaderPartProperty;
  121. begin
  122. for l in fPropertyMap do
  123. for p in l do
  124. aGen.AddProperty(p, false);
  125. end;
  126. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  127. procedure TengShaderGenerator.UpdateProperties;
  128. begin
  129. fPropertyMap.Clear;
  130. end;
  131. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  132. function TengShaderGenerator.ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String;
  133. begin
  134. result := inherited ParseIntern(aArgs, aParams);
  135. UpdateProperties;
  136. end;
  137. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  138. function TengShaderGenerator.TryGetProperty(const aName: String; out aValue: Variant): Boolean;
  139. var
  140. l: TengShaderPartPropertyList;
  141. begin
  142. l := fPropertyMap[aName];
  143. result := Assigned(l);
  144. if result
  145. then aValue := l.Value
  146. else aValue := unassigned;
  147. end;
  148. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  149. function TengShaderGenerator.TrySetProperty(const aName: String; const aValue: Variant): Boolean;
  150. var
  151. l: TengShaderPartPropertyList;
  152. begin
  153. l := fPropertyMap[aName];
  154. result := Assigned(l);
  155. if result then
  156. l.Value := aValue;
  157. end;
  158. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  159. procedure TengShaderGenerator.ListProperties(const aPropertyNames: TStrings);
  160. var
  161. s: String;
  162. begin
  163. for s in fPropertyMap.Keys do
  164. aPropertyNames.Add(s);
  165. end;
  166. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  167. procedure TengShaderGenerator.GenerateCode(const aCode: TengShaderCode);
  168. var
  169. args: TengShaderGeneratorArgs;
  170. sr: TengSearchResults;
  171. walker: TengSearchWalker;
  172. main: TengShaderPartMain;
  173. begin
  174. args := TengShaderGeneratorArgs.Create(self);
  175. try
  176. fPropertyMap.ApplyValues;
  177. GenerateCodeIntern(args);
  178. args.PushCode;
  179. sr := TengSearchResults.Create;
  180. walker := TengSearchWalker.Create(sr);
  181. try
  182. walker.SearchFlags := [sfSearchChildren, sfEvaluateIf];
  183. walker.ResultTypes := CengShaderPartArr.Create(TengShaderPartMain);
  184. walker.ChildrenDoNotLeave := CengShaderPartArr.Create(TengShaderGenerator);
  185. walker.ChildrenForceLeave := CengShaderPartArr.Create(TengShaderFile);
  186. walker.Run(self);
  187. if (self is TengShaderFile)
  188. then main := (ExtractSearchResult(self, TengShaderPartMain.GetTokenName, sr, []) as TengShaderPartMain)
  189. else main := (ExtractSearchResult(self, TengShaderPartMain.GetTokenName, sr) as TengShaderPartMain);
  190. if Assigned(main) then begin
  191. args.PushFlags((args.Flags * [gfAddProcedureItem, gfAddParameterItem]) + [gfGenerateProcedureCode, gfGenerateProcedureMain]);
  192. try
  193. main.GenerateCodeIntern(args);
  194. finally
  195. args.PopFlags;
  196. end;
  197. end;
  198. finally
  199. FreeAndNil(walker);
  200. FreeAndNil(sr);
  201. args.PopCode([pcfAppend, pcfAddEmptyLine]);
  202. end;
  203. args.GenerateProcedureCode;
  204. args.GenerateParameterCode(CengShaderPartArr.Create(TengShaderPartVar));
  205. args.GenerateParameterCode(CengShaderPartArr.Create(TengShaderPartVarying));
  206. args.GenerateParameterCode(CengShaderPartArr.Create(TengShaderPartUniform));
  207. args.PushCode;
  208. try
  209. args.GenerateMetaCode;
  210. finally
  211. args.PopCode([pcfPrepend, pcfAddEmptyLine]);
  212. end;
  213. args.GenerateCode(aCode);
  214. finally
  215. FreeAndNil(args);
  216. end;
  217. end;
  218. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  219. constructor TengShaderGenerator.Create(const aParent: TengShaderPart);
  220. begin
  221. inherited Create(aParent);
  222. fPropertyMap := TengShaderPartPropertyMap.Create(true);
  223. end;
  224. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  225. destructor TengShaderGenerator.Destroy;
  226. begin
  227. FreeAndNil(fPropertyMap);
  228. inherited Destroy;
  229. end;
  230. end.