Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

418 řádky
15 KiB

  1. unit uengShaderPartProc;
  2. {$mode objfpc}{$H+}
  3. {$I uengShaderFile.inc}
  4. interface
  5. uses
  6. Classes, SysUtils,
  7. uengShaderPart, uengShaderPartScope, uengShaderFileParser, uengShaderGeneratorArgs
  8. {$IFDEF USE_BITSPACE_UTILS}
  9. , uutlGenerics;
  10. {$ELSE}
  11. , fgl;
  12. {$ENDIF}
  13. type
  14. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  15. TengShaderPartProcParam = packed record
  16. Typ: String;
  17. Name: String;
  18. end;
  19. TengShaderPartProcParamList = specialize TutlSimpleList<TengShaderPartProcParam>;
  20. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  21. TengShaderPartProc = class(TengShaderPartScope)
  22. { Code Loading & Storage }
  23. private
  24. fName: String;
  25. fIsInline: Boolean;
  26. fParameters: TengShaderPartProcParamList;
  27. function GetParameter(const aIndex: Integer): TengShaderPartProcParam;
  28. function GetParameterCount: Integer;
  29. protected
  30. function GetHeaderText: String; virtual;
  31. function GetText: String; override;
  32. function ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; override;
  33. { Code Generation }
  34. protected
  35. function GenerateHeaderCode: String; virtual;
  36. procedure GenerateInlineCode(const aArgs: TengShaderGeneratorArgs); virtual;
  37. public
  38. procedure GenerateCodeIntern(const aArgs: TengShaderGeneratorArgs); override;
  39. { General }
  40. public
  41. property Name: String read fName;
  42. property IsInline: Boolean read fIsInline;
  43. property ParameterCount: Integer read GetParameterCount;
  44. property Parameters[const aIndex: Integer]: TengShaderPartProcParam read GetParameter;
  45. constructor Create(const aParent: TengShaderPart); override;
  46. destructor Destroy; override;
  47. { Class Members }
  48. public
  49. class function GetTokenName: String; override;
  50. end;
  51. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  52. TengShaderPartMain = class(TengShaderPartProc)
  53. { Code Loading & Storage }
  54. protected
  55. function GetHeaderText: String; override;
  56. function ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; override;
  57. { Code Generation }
  58. protected
  59. function GenerateHeaderCode: String; override;
  60. { General }
  61. public
  62. class function GetTokenName: String; override;
  63. end;
  64. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  65. TengShaderPartFunc = class(TengShaderPartProc)
  66. { Code Loading & Storage }
  67. private
  68. fReturnType: String;
  69. protected
  70. function GetHeaderText: String; override;
  71. function ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; override;
  72. { Code Generation }
  73. protected
  74. function GenerateHeaderCode: String; override;
  75. procedure GenerateInlineCode(const aArgs: TengShaderGeneratorArgs); override;
  76. { Class Methods }
  77. public
  78. class function GetTokenName: String; override;
  79. end;
  80. implementation
  81. uses
  82. RegExpr,
  83. uengShaderFileConstants, uengShaderFileTypes, uengShaderFileHelper;
  84. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  85. //TengShaderPartProc////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  86. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  87. function TengShaderPartProc.GetParameter(const aIndex: Integer): TengShaderPartProcParam;
  88. begin
  89. result := fParameters[aIndex];
  90. end;
  91. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  92. function TengShaderPartProc.GetParameterCount: Integer;
  93. begin
  94. result := fParameters.Count;
  95. end;
  96. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  97. function TengShaderPartProc.GetHeaderText: String;
  98. var
  99. p: TengShaderPartProcParam;
  100. begin
  101. result := TOKEN_CHAR_BEGIN + GetTokenName + ' ' + TOKEN_CHAR_QUOTE + fName + TOKEN_CHAR_QUOTE;
  102. for p in fParameters do begin
  103. result := result + ' ' + TOKEN_CHAR_QUOTE + p.Typ + TOKEN_CHAR_QUOTE +
  104. ' ' + TOKEN_CHAR_QUOTE + p.Name + TOKEN_CHAR_QUOTE;
  105. end;
  106. result := result + TOKEN_CHAR_END;
  107. end;
  108. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  109. function TengShaderPartProc.GetText: String;
  110. begin
  111. result := GetHeaderText +
  112. inherited GetText +
  113. TOKEN_CHAR_BEGIN + TOKEN_END + TOKEN_CHAR_END;
  114. end;
  115. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  116. function TengShaderPartProc.ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String;
  117. type
  118. TParseArgsState = (pasType, pasName);
  119. var
  120. i: Integer;
  121. state: TParseArgsState;
  122. param: TengShaderPartProcParam;
  123. begin
  124. if (aParams[0].Name <> GetTokenName) then with aParams[0] do
  125. raise EengInvalidToken.Create(ClassName, Name, Line, Col, Filename, self);
  126. if (aParams.Count < 2) then
  127. raise EengInvalidParamterCount.Create(GetTokenName, 2, -1, self);
  128. i := 2;
  129. result := '';
  130. fName := aParams[1].Name;
  131. state := pasType;
  132. fParameters.Clear;
  133. while (i < aParams.Count) do begin
  134. case state of
  135. pasType: begin
  136. if (aParams[i].Name <> TOKEN_INLINE) then begin
  137. param.Typ := aParams[i].Name;
  138. state := pasName;
  139. end else
  140. fIsInline := true;
  141. end;
  142. pasName: begin
  143. if (aParams[i].Name = TOKEN_INLINE) then begin
  144. with aParams[i] do
  145. raise EengInvalidParamter.Create('expected parameter name (found ' + TOKEN_INLINE + ')', Line, Col, Filename, self);
  146. end else begin
  147. param.Name := aParams[i].Name;
  148. fParameters.Add(param);
  149. state := pasType;
  150. end;
  151. end;
  152. end;
  153. inc(i);
  154. end;
  155. if (state <> pasType) then
  156. raise EengInvalidParamterCount.Create('invalid parameter count in ' + GetTokenName + '(expected multiple of 2)', self);
  157. result := inherited ParseIntern(aArgs, aParams);
  158. result := CheckEndToken(result, aArgs, self);
  159. end;
  160. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  161. function TengShaderPartProc.GenerateHeaderCode: String;
  162. var
  163. p: TengShaderPartProcParam;
  164. begin
  165. result := '';
  166. for p in fParameters do begin
  167. if (result <> '') then
  168. result := result + ', ';
  169. result := result + p.Typ + ' ' + p.Name;
  170. end;
  171. if (result = '') then
  172. result := 'void';
  173. result := 'void ' + fName + '(' + result + ')';
  174. end;
  175. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  176. procedure TengShaderPartProc.GenerateInlineCode(const aArgs: TengShaderGeneratorArgs);
  177. var
  178. p: TengShaderPartProcParam;
  179. old, new: TStringList;
  180. rx: TRegExpr;
  181. s: String;
  182. begin
  183. aArgs.PushCode;
  184. rx := TRegExpr.Create;
  185. old := TStringList.Create;
  186. new := TStringList.Create;
  187. try
  188. inherited GenerateCodeIntern(aArgs);
  189. // prepare old parameters
  190. for p in fParameters do
  191. old.Add(p.Name);
  192. // prepate new paramaters
  193. rx.Expression := '[^A-z0-9_]+';
  194. for s in aArgs.ProcParams do begin
  195. if rx.Exec(s)
  196. then new.Add('(' + s + ')')
  197. else new.Add(s);
  198. end;
  199. // replace parameters
  200. aArgs.ReplaceIdents(old, new);
  201. finally
  202. FreeAndNil(rx);
  203. FreeAndNil(old);
  204. FreeAndNil(new);
  205. aArgs.PopCode([pcfAppend]);
  206. end;
  207. end;
  208. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  209. procedure TengShaderPartProc.GenerateCodeIntern(const aArgs: TengShaderGeneratorArgs);
  210. var
  211. s, params: String;
  212. begin
  213. // generate inline code
  214. if (aArgs.Flags * [gfGenerateProcedureCall, gfGenerateProcedureCode] <> []) and
  215. ((gfGenerateInlineCode in aArgs.Flags) or fIsInline) then
  216. begin
  217. GenerateInlineCode(aArgs);
  218. // TODO: ignore next command end?!
  219. // generate code
  220. end else if (gfGenerateProcedureCode in aArgs.Flags) then begin
  221. aArgs
  222. .AddLineBreak
  223. .AddText(GenerateHeaderCode)
  224. .AddLineBreak
  225. .AddCommandEnd('{')
  226. .AddLineBreak
  227. .BeginBlock(4);
  228. try
  229. inherited GenerateCodeIntern(aArgs);
  230. finally
  231. aArgs
  232. .EndBlock
  233. .AddCommandEnd('}')
  234. .AddLineBreak;
  235. end;
  236. // generate call
  237. end else if (gfGenerateProcedureCall in aArgs.Flags) then begin
  238. params := '';
  239. for s in aArgs.ProcParams do begin
  240. if (params <> '') then
  241. params := params + ', ';
  242. params := params + s;
  243. end;
  244. aArgs.AddText(fName + '(' + params + ')');
  245. aArgs.AddProcedure(self);
  246. end;
  247. end;
  248. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  249. constructor TengShaderPartProc.Create(const aParent: TengShaderPart);
  250. begin
  251. inherited Create(aParent);
  252. fParameters := TengShaderPartProcParamList.Create(true);
  253. end;
  254. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  255. destructor TengShaderPartProc.Destroy;
  256. begin
  257. FreeAndNil(fParameters);
  258. inherited Destroy;
  259. end;
  260. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  261. class function TengShaderPartProc.GetTokenName: String;
  262. begin
  263. result := TOKEN_PROC;
  264. end;
  265. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  266. //TengShaderPartMain////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  267. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  268. function TengShaderPartMain.GetHeaderText: String;
  269. begin
  270. result := TOKEN_CHAR_BEGIN + GetTokenName + TOKEN_CHAR_END;
  271. end;
  272. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  273. function TengShaderPartMain.ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String;
  274. var
  275. p: TengTokenParameter;
  276. begin
  277. if (aParams[0].Name <> GetTokenName) then with aParams[0] do
  278. raise EengInvalidToken.Create(ClassName, Name, Line, Col, Filename, self);
  279. if (aParams.Count <> 1) then
  280. raise EengInvalidParamterCount.Create(GetTokenName, 1, self);
  281. result := '';
  282. p.Name := 'main';
  283. p.Quoted := false;
  284. p.Line := Line;
  285. p.Col := Col + Length(GetTokenName);
  286. aParams.Add(p);
  287. inherited ParseIntern(aArgs, aParams);
  288. end;
  289. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  290. function TengShaderPartMain.GenerateHeaderCode: String;
  291. begin
  292. result := 'void main(void)';
  293. end;
  294. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  295. class function TengShaderPartMain.GetTokenName: String;
  296. begin
  297. result := TOKEN_MAIN;
  298. end;
  299. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  300. //TengShaderPartFunc////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  301. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  302. function TengShaderPartFunc.GetHeaderText: String;
  303. var
  304. p: TengShaderPartProcParam;
  305. begin
  306. result := TOKEN_CHAR_BEGIN + GetTokenName + ' ' +
  307. TOKEN_CHAR_QUOTE + fReturnType + TOKEN_CHAR_QUOTE + ' ' +
  308. TOKEN_CHAR_QUOTE + fName + TOKEN_CHAR_QUOTE;
  309. for p in fParameters do
  310. result := result + ' ' + TOKEN_CHAR_QUOTE + p.Typ + TOKEN_CHAR_QUOTE
  311. + ' ' + TOKEN_CHAR_QUOTE + p.Name + TOKEN_CHAR_QUOTE;
  312. result := result + TOKEN_CHAR_END;
  313. end;
  314. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  315. function TengShaderPartFunc.ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String;
  316. begin
  317. if (aParams[0].Name <> GetTokenName) then with aParams[0] do
  318. raise EengInvalidToken.Create(ClassName, aParams[0].Name, Line, Col, Filename, self);
  319. if (aParams.Count < 3) then
  320. raise EengInvalidParamterCount.Create(GetTokenName, 3, self);
  321. fReturnType := aParams[1].Name;
  322. aParams.Delete(1);
  323. result := inherited ParseIntern(aArgs, aParams);
  324. end;
  325. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  326. function TengShaderPartFunc.GenerateHeaderCode: String;
  327. var
  328. p: TengShaderPartProcParam;
  329. begin
  330. result := '';
  331. for p in fParameters do begin
  332. if (result <> '') then
  333. result := result + ', ';
  334. result := result + p.Typ + ' ' + p.Name;
  335. end;
  336. if (result = '') then
  337. result := 'void';
  338. result := fReturnType + ' ' + fName + '(' + result + ')';
  339. end;
  340. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  341. procedure TengShaderPartFunc.GenerateInlineCode(const aArgs: TengShaderGeneratorArgs);
  342. var
  343. csi: TengShaderGeneratorArgs.TCodeStackItem;
  344. indent: Integer;
  345. begin
  346. csi := TengShaderGeneratorArgs.TCodeStackItem.Create;
  347. try
  348. indent := aArgs.ExtractCurrentCommand(csi);
  349. aArgs.PushCode;
  350. aArgs.BeginBlock;
  351. try
  352. inherited GenerateInlineCode(aArgs);
  353. finally
  354. aArgs.EndBlock;
  355. aArgs.AddText(StringOfChar(' ', indent));
  356. aArgs.ReplaceReturns(csi, fReturnType, fName);
  357. aArgs.PopCode([pcfAppend]);
  358. end;
  359. finally
  360. FreeAndNil(csi);
  361. end;
  362. end;
  363. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  364. class function TengShaderPartFunc.GetTokenName: String;
  365. begin
  366. result := TOKEN_FUNC;
  367. end;
  368. end.