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.

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